Unix Timestamps in Python

Python provides several built-in ways to work with Unix timestamps. Whether you are logging events, storing dates in a database, or parsing API responses, understanding how Python handles epoch time will save you from subtle bugs. This guide covers every common operation with practical code you can copy into your project.

Getting the Current Unix Timestamp

The two most common approaches use the time and datetime modules.

Using time.time()

import time

ts = time.time()
print(ts)  # 1711545600.123456

time.time() returns a float representing seconds since the Unix epoch (January 1, 1970 00:00:00 UTC). The fractional part gives you sub-second precision. If you only need an integer:

ts = int(time.time())  # 1711545600

Using datetime.now().timestamp()

from datetime import datetime

ts = datetime.now().timestamp()
print(ts)  # 1711545600.123456

This returns the same float value. The difference is that datetime.now() creates a datetime object first, which is useful when you need both the timestamp and a formatted date.

Which should you use? Prefer time.time() when you only need the raw number. Use datetime.now().timestamp() when you are already working with datetime objects.

Converting a Timestamp to a Datetime

Local Time

from datetime import datetime

ts = 1711545600
dt = datetime.fromtimestamp(ts)
print(dt)  # 2024-03-27 12:00:00 (depends on your local timezone)

fromtimestamp() converts the epoch value into a datetime object using your system's local timezone. This is fine for display purposes but can produce different results on different machines.

UTC Time

from datetime import datetime, timezone

ts = 1711545600
dt = datetime.fromtimestamp(ts, tz=timezone.utc)
print(dt)  # 2024-03-27 12:00:00+00:00

Always pass tz=timezone.utc when you need a consistent result regardless of where the code runs. The older datetime.utcfromtimestamp() method is deprecated since Python 3.12 because it returns a naive datetime that can be confused with local time.

Converting a Datetime to a Timestamp

from datetime import datetime, timezone

dt = datetime(2024, 3, 27, 12, 0, 0, tzinfo=timezone.utc)
ts = dt.timestamp()
print(ts)  # 1711540800.0

If your datetime is timezone-aware, .timestamp() correctly computes the UTC epoch. If it is naive (no tzinfo), Python assumes local time, which can cause unexpected shifts.

Handling Timezones

Using zoneinfo (Python 3.9+)

The zoneinfo module is the modern, standard-library solution for timezone handling.

from datetime import datetime
from zoneinfo import ZoneInfo

# Create a timezone-aware datetime
dt_tokyo = datetime(2024, 3, 27, 21, 0, 0, tzinfo=ZoneInfo("Asia/Tokyo"))
dt_ny = dt_tokyo.astimezone(ZoneInfo("America/New_York"))

print(dt_tokyo)  # 2024-03-27 21:00:00+09:00
print(dt_ny)     # 2024-03-27 08:00:00-04:00

# Both produce the same timestamp
print(dt_tokyo.timestamp())  # 1711540800.0
print(dt_ny.timestamp())     # 1711540800.0

Using pytz (Legacy)

If you are on Python 3.8 or earlier, or maintaining existing code that uses pytz:

import pytz
from datetime import datetime

tz = pytz.timezone("US/Eastern")
dt = tz.localize(datetime(2024, 3, 27, 8, 0, 0))
print(dt.timestamp())  # 1711540800.0

Important: Never pass a pytz timezone directly to the datetime constructor. Always use tz.localize(). This is the most common pytz bug:

# WRONG - produces incorrect offset for many timezones
dt = datetime(2024, 3, 27, 8, 0, 0, tzinfo=pytz.timezone("US/Eastern"))

# CORRECT
dt = pytz.timezone("US/Eastern").localize(datetime(2024, 3, 27, 8, 0, 0))

Millisecond Timestamps

Some APIs (JavaScript, Java, many REST endpoints) use millisecond timestamps -- 13-digit numbers instead of 10.

import time

# Current time in milliseconds
ms = int(time.time() * 1000)
print(ms)  # 1711545600123

# Convert milliseconds back to datetime
from datetime import datetime, timezone
ts_ms = 1711545600123
dt = datetime.fromtimestamp(ts_ms / 1000, tz=timezone.utc)
print(dt)  # 2024-03-27 12:00:00.123000+00:00

The rule is simple: divide by 1000 to go from milliseconds to seconds, multiply by 1000 to go the other way.

Formatting Timestamps as Strings

from datetime import datetime, timezone

dt = datetime.fromtimestamp(1711545600, tz=timezone.utc)

print(dt.isoformat())                   # 2024-03-27T12:00:00+00:00
print(dt.strftime("%Y-%m-%d %H:%M:%S")) # 2024-03-27 12:00:00
print(dt.strftime("%B %d, %Y"))         # March 27, 2024

Parsing Date Strings into Timestamps

from datetime import datetime, timezone

date_str = "2024-03-27T12:00:00Z"
dt = datetime.fromisoformat(date_str.replace("Z", "+00:00"))
print(dt.timestamp())  # 1711540800.0

In Python 3.11+, fromisoformat() handles the Z suffix directly. On older versions, replace Z with +00:00 as shown above.

Common Gotchas

GotchaFix
utcfromtimestamp() returns naive datetimeUse fromtimestamp(ts, tz=timezone.utc) instead
pytz timezone in constructor gives wrong offsetUse tz.localize() instead
Naive datetime treated as local time by .timestamp()Always attach a timezone before calling .timestamp()
Mixing seconds and millisecondsCheck digit count: 10 digits = seconds, 13 = milliseconds
strftime on Windows does not support %-dUse %#d on Windows or format manually

Quick Reference

import time
from datetime import datetime, timezone

# Current timestamp (seconds)
time.time()

# Current timestamp (milliseconds)
int(time.time() * 1000)

# Timestamp to UTC datetime
datetime.fromtimestamp(ts, tz=timezone.utc)

# Datetime to timestamp
dt.timestamp()

# ISO format string
dt.isoformat()

Need to quickly verify a conversion? Try it online with DevToolBox -- paste any timestamp and see the result instantly without writing a single line of code.