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

  1. Search your code: grep -rn "utcnow\|utcfromtimestamp" .
  2. Replace with datetime.now(timezone.utc) and datetime.fromtimestamp(ts, tz=timezone.utc).
  3. Store and compare only aware datetimes; convert to a local zone only when showing a time to a person.
  4. Run your tests with python -W error::DeprecationWarning to catch leftovers.

Sources

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?