Unix timestamps and clocks

datetime · Practical · 9 min

APIs, databases and file systems often exchange times as seconds since the epoch.

A Unix timestamp counts seconds since 1970-01-01 00:00:00 UTC (the epoch). It's time-zone independent, which makes it a compact interchange format.

Conversions:

  • dt.timestamp() turns an aware datetime into a float timestamp. On a naive datetime it assumes local time, a frequent source of hour-sized bugs.
  • datetime.fromtimestamp(ts, tz=UTC) builds an aware datetime. Without tz it returns a naive local time.
  • time.time() returns the current timestamp directly; time.time_ns() returns integer nanoseconds.

JavaScript and many APIs use milliseconds: divide by 1000 before fromtimestamp. A value around 1.7 billion is seconds; around 1.7 trillion is milliseconds.

Which clock to use:

  • time.time() / datetime.now(UTC): wall-clock time. It can jump backwards or forwards when NTP or a user adjusts the clock.
  • time.monotonic(): never goes backwards; use it for timeouts and intervals.
  • time.perf_counter(): monotonic with the highest resolution; use it for benchmarking.

Python's datetime has no leap seconds: like Unix time, it assumes every day has exactly 86,400 seconds.

Example

import time
from datetime import UTC, datetime

dt = datetime(2025, 3, 1, 12, 0, tzinfo=UTC)
ts = dt.timestamp()
print(ts)                                   # 1740830400.0
print(datetime.fromtimestamp(ts, tz=UTC))   # 2025-03-01 12:00:00+00:00

js_ms = 1740830400123                       # milliseconds from a JS client
print(datetime.fromtimestamp(js_ms / 1000, tz=UTC))
# 2025-03-01 12:00:00.123000+00:00

start = time.monotonic()
time.sleep(0.05)
elapsed = time.monotonic() - start
print(0.04 < elapsed < 1)                   # True
print(isinstance(time.time_ns(), int))      # True

Remember

  • Timestamps are seconds since 1970-01-01 UTC, independent of zones
  • Always pass tz=UTC to fromtimestamp and call timestamp() on aware values
  • Use monotonic or perf_counter for durations, not wall-clock time

Watch out for

  • Feeding millisecond timestamps to fromtimestamp, producing dates tens of thousands of years ahead (or an error).

Check yourself

  1. Why use time.monotonic() rather than time.time() to implement a 30-second timeout?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.python.org/3/library/datetime.html#datetime.datetime.fromtimestamp