datetime.fromtimestamp / utcfromtimestamp

Epoch seconds in, datetime out. With tz=UTC the answer is the same on every machine; without tz it is the machine's local time, and date.fromtimestamp is always local.

datetime class methodPython 2.3+ (utcfromtimestamp deprecated 3.12)Live demo
Common call
datetime.fromtimestamp(ts, UTC)
Returns
datetime.datetime(…, tzinfo=datetime.timezone.utc)
Replaces
datetime.utcfromtimestamp(ts) (naive, deprecated) and time.gmtime(ts)
Watch out
Milliseconds (JavaScript Date.now()) must be divided by 1000
datetime.fromtimestamp(timestamptimestamp — Seconds since 1970-01-01T00:00:00Z. Fractions become microseconds, rounded half to even.type: int | float · required, tztz — None: naive local time (depends on the machine). A tzinfo: aware result in that zone. date.fromtimestamp has no tz.type: tzinfo | None · default: None=None)
→ datetime

Demo

Live evaluation
A timestamp shown at a fixed offset. The instant is the same; only the wall-clock reading changes.
Try:
Inputs
tsintseconds since the epoch
hoursintoffset in hours
Code
from datetime import datetime, timedelta, timezone
datetime.fromtimestamp(0, timezone(timedelta(hours=0))).isoformat()
Result
'1970-01-01T00:00:00+00:00'

1790683200 is 2026-09-29 12:00 UTC, shown here at +02:00 as 14:00. 86400000 is one day in milliseconds, but read as seconds it is 1000 days: 1972-09-27. Millisecond timestamps of today overflow completely — Linux raises ValueError for the year beyond 9999 (as this demo does), Windows OSError: [Errno 22] Invalid argument.

Parameters

NameTypeRequiredDescription
timestampint | floatyesSeconds since 1970-01-01T00:00:00Z. Fractions become microseconds, rounded half to even.
tztzinfo | Noneno (None)None: naive local time (depends on the machine). A tzinfo: aware result in that zone. date.fromtimestamp has no tz.

Return value

datetime — Aware in tz when tz is given; otherwise naive local time. date.fromtimestamp returns the local date.

Common patterns

Unix timestamp to aware UTC
Works identically everywhere.
from datetime import datetime, UTC
dt = datetime.fromtimestamp(ts, UTC)
Milliseconds from JavaScript or Java
Divide by 1000 first (a float keeps the milliseconds).
from datetime import datetime, UTC
dt = datetime.fromtimestamp(ms / 1000, UTC)
File modification time
os.stat gives epoch seconds.
import os
from datetime import datetime, UTC
modified = datetime.fromtimestamp(os.stat(path).st_mtime, UTC)

Examples

1. The epoch
from datetime import datetime, UTC datetime.fromtimestamp(0, UTC)
Returns
datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)
2. At a fixed offset
from datetime import datetime, timedelta, timezone datetime.fromtimestamp(1790690400, timezone(timedelta(hours=2)))
Returns
datetime.datetime(2026, 9, 29, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200)))
3. Fractions become microseconds
from datetime import datetime, UTC datetime.fromtimestamp(1790690400.5, UTC)
Returns
datetime.datetime(2026, 9, 29, 14, 0, 0, 500000, tzinfo=datetime.timezone.utc)
4. Round trip with timestamp()
from datetime import datetime, UTC dt = datetime(2026, 9, 29, 12, tzinfo=UTC) datetime.fromtimestamp(dt.timestamp(), UTC) == dt
Returns
True
5. Strings are not accepted
from datetime import datetime, UTC datetime.fromtimestamp('0', UTC)
Returns
TypeError: 'str' object cannot be interpreted as an integer
6. Beyond time_t
from datetime import datetime, UTC datetime.fromtimestamp(1e20, UTC)
Returns
OverflowError: timestamp out of range for platform time_t
7. utcfromtimestamp warns (3.12+)
import warnings from datetime import datetime with warnings.catch_warnings(record=True) as caught: warnings.simplefilter("always") naive = datetime.utcfromtimestamp(0) (naive, caught[0].category.__name__)
Returns
(datetime.datetime(1970, 1, 1, 0, 0), 'DeprecationWarning')

Pitfalls

1. utcfromtimestamp returns naive UTC
The fields are UTC but tzinfo is None, so timestamp() on the result would treat them as local time. Deprecated since 3.12.
utcfromtimestamp
import warnings
from datetime import datetime
with warnings.catch_warnings():
    warnings.simplefilter("ignore")
    dt = datetime.utcfromtimestamp(1790683200)
dt.tzinfo is None
True
fromtimestamp(ts, UTC)
from datetime import datetime, UTC
datetime.fromtimestamp(1790683200, UTC)
datetime.datetime(2026, 9, 29, 12, 0, tzinfo=datetime.timezone.utc)
2. Milliseconds instead of seconds
JavaScript, Java and many APIs use milliseconds. Read as seconds the value is 1000 times too far from 1970: one day becomes 1000 days, and current timestamps overflow past year 9999.
ms as seconds
from datetime import datetime, UTC
datetime.fromtimestamp(86400000, UTC)
datetime.datetime(1972, 9, 27, 0, 0, tzinfo=datetime.timezone.utc)
/ 1000
from datetime import datetime, UTC
datetime.fromtimestamp(86400000 / 1000, UTC)
datetime.datetime(1970, 1, 2, 0, 0, tzinfo=datetime.timezone.utc)

When to use

Use it
  • Epoch values from databases, logs, os.stat, APIs
  • Always with tz (usually UTC) unless you really want machine-local time
Reach for something else
  • utcfromtimestamp → fromtimestamp(ts, UTC)
  • ISO 8601 text → fromisoformat

Notes

CPython impl
The timestamp is split into seconds and microseconds (round half to even), converted with gmtime() when tz is given, then tz.fromutc(); without tz, localtime() is used
Platforms
The valid range is the C library's: on Windows timestamps before 1969-12-31T12:00Z or after 3001-01-19T21:59:59Z raise OSError: [Errno 22] Invalid argument; Linux accepts the whole 1..9999 range
Deprecation
utcfromtimestamp() emits DeprecationWarning since 3.12: "datetime.datetime.utcfromtimestamp() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.fromtimestamp(timestamp, datetime.UTC)."

FAQ

datetime.fromtimestamp(ts, UTC) for an aware UTC datetime (use timezone.utc before Python 3.11). Without the tz argument you get naive local time of the machine running the code.