Epoch Converter in Python
Convert Unix timestamps to dates and back in Python: the idiomatic code, the gotchas, and a live converter.
How do you convert a Unix timestamp to a datetime in Python?
Call datetime.fromtimestamp(ts, tz=timezone.utc) to get an aware UTC datetime, and dt.timestamp() to go back to epoch seconds. Python expects seconds, so divide a 13-digit millisecond value by 1000 first or the date lands tens of thousands of years in the future.
from datetime import datetime, timezone ts = 1777010400 dt = datetime.fromtimestamp(ts, tz=timezone.utc) print(dt) # 2026-04-24 06:00:00+00:00
from datetime import datetime, timezone dt = datetime(2026, 4, 24, 6, 0, 0, tzinfo=timezone.utc) ts = int(dt.timestamp()) print(ts) # 1777010400
Naive datetimes are the Python trap
Python happily builds datetime objects with no timezone attached, and those naive objects are where almost every off-by-hours bug starts. A naive datetime is interpreted as local time the moment you call .timestamp() on it, so the same code produces different epochs on a laptop in Karachi and a server in us-east-1. Always pass tz=timezone.utc to fromtimestamp and always attach tzinfo when constructing datetimes by hand.
The older shortcuts made this worse. datetime.utcnow() and datetime.utcfromtimestamp() return naive objects that look like UTC but carry no zone, and both are deprecated as of Python 3.12. The modern replacements are datetime.now(timezone.utc) and datetime.fromtimestamp(ts, tz=timezone.utc). If you see utcfromtimestamp in a codebase, treat it as a bug waiting to be scheduled.
Seconds in, seconds out
Python's epoch convention is seconds as a float, matching time.time(). That clashes with anything that crossed a JavaScript boundary, because browser code emits 13-digit milliseconds. If fromtimestamp raises no error but prints a year like 58274, you fed it milliseconds; divide by 1000 first. Going the other way, dt.timestamp() returns a float with sub-second precision, so wrap it in int() before putting it in a JWT exp claim or any API that validates whole seconds.
Frequently asked
- Why is my Python datetime off by several hours?
- You almost certainly converted through a naive datetime, which Python interprets in the machine's local timezone. Pass tz=timezone.utc to fromtimestamp and attach tzinfo when building datetimes so the conversion is anchored to UTC instead of wherever the code happens to run.
- Is datetime.utcfromtimestamp deprecated?
- Yes, since Python 3.12, along with utcnow(). Both return naive datetimes that silently lose the UTC context. Use datetime.fromtimestamp(ts, tz=timezone.utc) and datetime.now(timezone.utc) instead; they return aware objects that survive further arithmetic and formatting correctly.
- How do I get milliseconds since epoch in Python?
- Use int(time.time() * 1000), or for an existing aware datetime, int(dt.timestamp() * 1000). Python has no built-in millisecond epoch function because its native convention is float seconds, so the multiplication is idiomatic and expected.
More in this series
// The subscription desk
The Inference Report
The weekly briefing for AI engineers: model releases, pricing moves, benchmarks, and the news that changes what you should build with and what it costs. Every Tuesday, 5-minute read. No fluff.
Join AI engineers who stopped overpaying for tokens. Unsubscribe anytime.