Unix Time in Python
Python exposes epoch time in two layers: the time module returns the raw number, and the datetime module converts between that number and calendar dates. Most bugs come from mixing the two carelessly — specifically from naive datetimes that silently assume local time.
The current Unix timestamp is time.time(). It returns a float with sub-second precision; wrap it in int() for whole seconds, or multiply by 1000 and truncate for milliseconds.
Getting the current timestamp
- import time; time.time() — seconds as a float, e.g. 1774137600.482.
- int(time.time()) — whole seconds, the form APIs and JWTs usually want.
- time.time_ns() — nanoseconds as an integer, immune to float rounding.
- From an aware datetime: datetime.now(timezone.utc).timestamp() gives the same number via the calendar layer.
Timestamp to date and back
Always attach a timezone. datetime.fromtimestamp(ts, tz=timezone.utc) returns an aware UTC datetime; passing no tz gives you the machine’s local time with no marker saying so, which is how the same timestamp prints differently on a laptop and a server.
The reverse direction is datetime(2038, 1, 19, 3, 14, 7, tzinfo=timezone.utc).timestamp(). On a naive datetime, .timestamp() interprets the value as local time — the single most common source of off-by-hours bugs in Python time handling.
The utcnow and utcfromtimestamp deprecation
datetime.utcnow() and datetime.utcfromtimestamp() are deprecated since Python 3.12, because they return naive datetimes that claim to be UTC but carry no tzinfo. The replacements are datetime.now(timezone.utc) and datetime.fromtimestamp(ts, tz=timezone.utc). Migrating is usually a find-and-replace, and it removes a whole class of ambiguity.
Milliseconds, strings and pandas
- JavaScript-style millisecond timestamps: divide by 1000 before fromtimestamp, or multiply a Python timestamp by 1000 before sending. Thirteen digits means milliseconds.
- Formatting: aware_dt.strftime('%Y-%m-%d %H:%M:%S') for display, aware_dt.isoformat() for machine-readable output.
- Parsing ISO strings: datetime.fromisoformat() handles offsets like +00:00, and since Python 3.11 also a trailing Z.
- pandas: pd.to_datetime(series, unit='s', utc=True) converts whole columns of epoch seconds; unit='ms' for milliseconds.
Frequently asked questions
How do I get the current Unix timestamp in Python?
Call time.time() for seconds as a float, or int(time.time()) for whole seconds. time.time_ns() returns nanoseconds as an integer.
How do I convert a Unix timestamp to a datetime in Python?
Use datetime.fromtimestamp(ts, tz=timezone.utc). Always pass a timezone — without one Python uses the machine’s local time and returns a naive datetime with no marker saying so.
Why is datetime.utcnow() deprecated?
Since Python 3.12, because it returns a naive datetime that represents UTC but carries no tzinfo, which breaks .timestamp() and comparisons. Use datetime.now(timezone.utc) instead.
How do I get milliseconds since epoch in Python?
int(time.time() * 1000), or time.time_ns() // 1_000_000 to avoid float rounding entirely.
How do I convert a datetime to a Unix timestamp in Python?
Call .timestamp() on an aware datetime. On naive datetimes it assumes local time, so attach tzinfo=timezone.utc first if the value is meant to be UTC.