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.
time.time(): a float, so truncate deliberately
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
fromtimestamp() and the naive-local trap
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
Back to a timestamp: timestamp() on aware objects only
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 in Python: 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.
Python pitfalls: aware vs naive mixing
- 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.
Check the Python output in the live converter
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 · Contact · Methodology
the same task in every language
JavaScript · Python · PHP · SQL · Go · Java · C# · Rust · C++ · PowerShell
the Python quick check is epoch time converter — handy for verifying datetime arithmetic against an independent implementation.