Guides · 8 min read
Unix timestamps in Python: a practical guide
Python has three different time APIs and they all do slightly different things. Here is when to use time.time, when to use datetime, when to use Arrow or Pendulum, and the pitfalls in between.
Published 22 April 2026
Python’s date and time story is the result of about 25 years of evolution. The standard library has time, datetime, calendar, and zoneinfo, plus more in third-party land. They overlap, they sometimes contradict each other, and the canonical advice has shifted twice — once for pytz, and once for zoneinfo in Python 3.9.
This guide is the modern, opinionated take: what to use today, what to skip, and how to deal with Unix timestamps without writing bugs.
Getting the current Unix timestamp
The shortest version is time.time(), which returns a float of seconds since the epoch:
import time
seconds = time.time()
# 1745301600.847123
time.time() returns sub-second precision in a 64-bit float, but the trailing digits aren’t always meaningful — different platforms have different clock resolutions. Don’t rely on it as a microsecond clock; use time.time_ns() (added in 3.7) if you want nanoseconds in an integer:
nanos = time.time_ns() # int, nanoseconds since 1970
millis = time.time_ns() // 1_000_000
If you only want integer seconds:
seconds = int(time.time())
datetime — the modern way
For most application code, datetime is what you want. It is calendar-aware, timezone-aware (since Python 3.9 with zoneinfo), and produces nice ISO strings.
from datetime import datetime, timezone
now = datetime.now(timezone.utc) # timezone-aware UTC
print(now.timestamp()) # 1745301600.847123 — seconds since epoch
print(now.isoformat()) # "2026-04-22T08:00:00.847123+00:00"
Always pass tz=timezone.utc (or another zone) explicitly. A “naive” datetime — one without a timezone — is a bug magnet. .timestamp() on a naive datetime assumes local time, which means the same code produces different results on different machines.
# Avoid: naive datetime.
naive = datetime.now() # local time, no tzinfo
naive.timestamp() # depends on the host's TZ env var
# Prefer: timezone-aware.
aware = datetime.now(timezone.utc)
aware.timestamp() # always the right number
Converting a Unix timestamp to a datetime
from datetime import datetime, timezone
ts = 1745301600
d = datetime.fromtimestamp(ts, tz=timezone.utc)
# datetime(2026, 4, 22, 8, 0, 0, tzinfo=timezone.utc)
Two important details:
datetime.fromtimestamp(ts)without atzargument returns a naive datetime in local time. Almost always wrong.datetime.utcfromtimestamp(ts)returns a naive datetime in UTC. Less wrong, but still naive — don’t use it. It’s deprecated in 3.12.
For milliseconds, divide before converting:
ms = 1745301600847
d = datetime.fromtimestamp(ms / 1000, tz=timezone.utc)
If you have a 13-digit number, it is almost certainly milliseconds. There’s a whole guide on telling the units apart.
Working with timezones (zoneinfo)
Python 3.9 added zoneinfo, which uses the IANA timezone database that ships with your operating system. It replaced the old pytz advice and is now the canonical way to do timezones.
from datetime import datetime
from zoneinfo import ZoneInfo
oslo = ZoneInfo("Europe/Oslo")
now = datetime.now(oslo)
print(now) # 2026-04-22 10:00:00+02:00
print(now.utcoffset()) # 2:00:00 — DST is honoured
# Convert between zones:
ny = now.astimezone(ZoneInfo("America/New_York"))
print(ny) # 2026-04-22 04:00:00-04:00
# Same instant either way:
print(now.timestamp() == ny.timestamp()) # True
If you’re on Python 3.8 or earlier, you need either pytz or dateutil. Upgrade if you can — the pytz API is famously confusing (localize() vs astimezone()), and zoneinfo cleans it all up.
On Windows, you may also need to install tzdata:
pip install tzdata
Linux and macOS have the IANA database installed system-wide.
ISO 8601 round-trips
datetime parses and formats ISO 8601 cleanly:
# Format
now.isoformat()
# "2026-04-22T10:00:00+02:00"
# Parse (Python 3.11+)
datetime.fromisoformat("2026-04-22T10:00:00+02:00")
# Parse a "Z"-suffixed string (Python 3.11+ supports this directly)
datetime.fromisoformat("2026-04-22T08:00:00Z")
For Python 3.10 and earlier, fromisoformat is more limited. The robust pre-3.11 incantation:
from datetime import datetime
import re
s = "2026-04-22T08:00:00Z"
d = datetime.fromisoformat(s.replace("Z", "+00:00"))
When to reach for a library
The standard library covers 90% of cases. Reach for an external library when you need:
- Robust parsing of arbitrary user input.
dateutil(pip install python-dateutil) handles “April 22, 2026”, “next Friday”, and most everything else you’ll encounter in user-entered strings. - Friendly relative formatting (“3 days ago”, “in 2 hours”).
humanizeis a small dependency that does this well. - A nicer overall API.
pendulum(pip install pendulum) andarrow(pip install arrow) both wrapdatetimewith a more fluent interface and built-in parsing. They’re great if you do a lot of date math; overkill if you only need to format two timestamps a day.
If you find yourself using dateutil heavily, consider whether pendulum would consolidate it.
The five things to remember
- Use
datetime.now(timezone.utc), notdatetime.now(). Naive datetimes are bugs waiting to happen. - Use
datetime.fromtimestamp(ts, tz=timezone.utc), not the barefromtimestamp(ts). - Use
zoneinfofor timezone work on Python 3.9+.pytzadvice is obsolete. time.time_ns()if you need integer nanoseconds;time.time()if you’re fine with a float in seconds.isoformat()for output,fromisoformat()for input. Stick with ISO 8601 strings on the wire.
A reference snippet
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
# Now in seconds (int) and as ISO 8601 (str):
seconds = int(datetime.now(timezone.utc).timestamp())
iso = datetime.now(timezone.utc).isoformat()
# Parse a timestamp in seconds:
ts = 1745301600
d = datetime.fromtimestamp(ts, tz=timezone.utc)
# Convert to Oslo time:
oslo_time = d.astimezone(ZoneInfo("Europe/Oslo"))
# Pretty print:
print(oslo_time.strftime("%A, %d %B %Y at %H:%M %Z"))
# "Wednesday, 22 April 2026 at 10:00 CEST"
If you have a number on hand and want to sanity-check what date it represents, paste it into the Unixdates converter and you’ll get the result in your local timezone, UTC, and ISO 8601 — all at once.
Need to convert a timestamp right now? Try the Unixdates converter — auto-detects seconds, milliseconds and microseconds.