FreeAI.DevTools

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.

Epoch to date (Python)
from datetime import datetime, timezone

ts = 1777010400
dt = datetime.fromtimestamp(ts, tz=timezone.utc)
print(dt)  # 2026-04-24 06:00:00+00:00
Date to epoch (Python)
from datetime import datetime, timezone

dt = datetime(2026, 4, 24, 6, 0, 0, tzinfo=timezone.utc)
ts = int(dt.timestamp())
print(ts)  # 1777010400
Now:

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.