Python Unix Timestamp: time, datetime & Timezone-Aware Epochs
Python gives you a floating-point epoch in seconds and a datetime module with two very different kinds of objects. The naive-vs-aware distinction is where Python timestamp code goes wrong more than anywhere else — this guide makes it concrete.
Get the current Unix timestamp
time.time() returns a float in seconds since the epoch. Because
it is a float, a simple int(time.time()) gives whole seconds, and multiplying by
1000 before truncating gives milliseconds.
import time
sec = int(time.time()) # whole seconds, e.g. 1767225600
ms = int(time.time() * 1000) # milliseconds
print(time.time()) # float with microseconds: 1767225600.123456
Convert a timestamp to a datetime
datetime.fromtimestamp() is the trap: without a tz argument it
returns a naive local datetime — the same number means different wall-clock
times on different machines. Always pass tz=timezone.utc for a deterministic
result, or tz=ZoneInfo("Asia/Kolkata") for a specific zone.
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
ts = 1767225600
naive_local = datetime.fromtimestamp(ts) # ⚠ depends on the machine's tz
aware_utc = datetime.fromtimestamp(ts, tz=timezone.utc) # 2026-01-01 00:00:00+00:00
aware_ist = datetime.fromtimestamp(ts, tz=ZoneInfo("Asia/Kolkata")) # 05:30+05:30
print(datetime.utcfromtimestamp(ts)) # DEPRECATED, and it returns a NAIVE object
Convert a datetime back to a timestamp
Only aware datetimes have a well-defined timestamp(). Calling it
on a naive datetime makes Python assume local time — silently. If you have a naive
object you know is UTC, attach the zone first with replace(tzinfo=timezone.utc).
from datetime import datetime, timezone
aware = datetime(2026, 1, 1, tzinfo=timezone.utc)
aware.timestamp() # 1767225600.0 ✓
naive = datetime(2026, 1, 1) # no zone
naive.timestamp() # interpreted as LOCAL time — wrong result
naive.replace(tzinfo=timezone.utc).timestamp() # 1767225600.0 ✓ explicit
Naive vs aware: the two kinds of datetime
- Naive — a wall-clock reading with no zone attached. It cannot be compared with aware datetimes (raises
TypeError) and has no real instant. - Aware — carries a
tzinfo(UTC, a fixed offset, or a namedZoneInfozone) and represents an actual instant. - Rule of thumb: store and transmit UTC (aware), convert to a named zone only for display.
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
now = datetime.now(timezone.utc) # aware UTC
ist = now.astimezone(ZoneInfo("Asia/Kolkata")) # same instant, other clock
ist.utcoffset() # datetime.timedelta(seconds=19800)
Native precision: microseconds
time.time() and datetime.timestamp() carry microsecond precision on
CPython (the OS clock permitting). There is no native millisecond integer type — you derive it
as int(time.time() * 1000), which is exactly what this site's
converter detects from a 13-digit value.
Common pitfalls
- fromtimestamp without tz — naive local output; tests pass on your machine, fail on the server.
- timestamp() on naive objects — silently uses the local zone.
- utcfromtimestamp — deprecated in 3.12 and still returns naive; use
fromtimestamp(ts, tz=timezone.utc). - Mixing aware and naive — comparisons raise
TypeError; normalize everything to aware UTC.
Try it live
Check any timestamp against these snippets in the epoch converter, or grab the current value from the Python snippet tab on the homepage.
First published · Last reviewed · Maintained and developed by the Real Epoch Converter team · [email protected] · Contact · Methodology
Unix time in every language
JavaScript · Python · PHP · SQL · Go · Java · C# · Rust · C++ · PowerShell
Prefer the point-and-click version? The epoch time converter on the home page handles seconds, milliseconds, and microseconds in any timezone — every snippet on this page produces the same value that tool shows.