If you upgraded to Python 3.12 and your logs suddenly show this, you are not alone:
DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version.
Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
The fix is one line, but it is worth understanding why, because the old call hides a real bug.
The problem: utcnow() returns a "naive" datetime
from datetime import datetime
a = datetime.utcnow()
print(a.tzinfo) # None -> naive: Python does not know this is UTC
The value is UTC, but nothing in the object says so. Mix it with an aware datetime and you get a crash:
from datetime import datetime, timezone
naive = datetime.utcnow()
aware = datetime.now(timezone.utc)
print(aware > naive)
# TypeError: can't compare offset-naive and offset-aware datetimes
Worse, calling .timestamp() on a naive datetime assumes your machine's local time zone, so datetime.utcnow().timestamp() can be off by hours on a laptop that is not set to UTC.
The fix
from datetime import datetime, timezone
now = datetime.now(timezone.utc) # works on every Python 3 version
# Python 3.11+ also has the shorter alias: datetime.now(datetime.UTC)
print(now.tzinfo) # UTC
print(now.isoformat()) # 2026-10-30T15:12:48.123456+00:00
The same applies to utcfromtimestamp():
# old
datetime.utcfromtimestamp(1_700_000_000)
# new
datetime.fromtimestamp(1_700_000_000, tz=timezone.utc)
Parsing timestamps from APIs
Many APIs return strings ending in Z. Since Python 3.11, fromisoformat accepts it and gives you an aware datetime:
from datetime import datetime
dt = datetime.fromisoformat("2026-10-29T13:02:03Z")
print(dt.tzinfo) # UTC
On older versions, replace the suffix first: s.replace("Z", "+00:00").
Quick migration checklist
- Search your code:
grep -rn "utcnow\|utcfromtimestamp" . - Replace with
datetime.now(timezone.utc)anddatetime.fromtimestamp(ts, tz=timezone.utc). - Store and compare only aware datetimes; convert to a local zone only when showing a time to a person.
- Run your tests with
python -W error::DeprecationWarningto catch leftovers.
Sources
- Python docs,
datetime.utcnow()deprecation note: https://docs.python.org/3/library/datetime.html#datetime.datetime.utcnow - Python 3.12 what's new: https://docs.python.org/3/whatsnew/3.12.html
This article was written with AI assistance and checked by the author.
Have you hit a time zone bug in production that only showed up on someone else's machine? What was the cause?
Top comments (0)