- An update on November 20, 2023
Success! The datetime.utcnow
function is deprecated in Python 3.12 along with datetime.utcfromtimestamp
. It may not be soon, but one day, these functions will be gone from maintained codebases.
The Python datetime.utcnow()
classmethod is harmful and should be replaced with:
from datetime import datetime, timezone
datetime.now(timezone.utc)
Naive Time Traveling
What makes utcnow()
so dangerous? Although the function gives the correct time in the UTC timezone, the returned datetime
does not include a timezone:
from datetime import datetime
now = datetime.utcnow()
now.tzinfo is None # True
These timezone-less datetime
instances are referred to as naive, and a naive datetime
can have unexpected behavior. For instance, the timestamp()
method of a datetime
instance will assume that any naive datetime
is local time! Although you might not notice this difference on a server set to UTC time, any timestamps will be off by your local time’s UTC offset. Here’s the offset in the US/Mountain
timezone:
from datetime import datetime
datetime.now(timezone.utc).timestamp() - datetime.utcnow().timestamp() # -21600
That puts the utcnow
timestamp 6 hours into the future! If you’re interacting with a service that expects a UTC-based unix timestamp, you’re likely to encounter undefined behavior. Since the naive UTC datetime is assuming that it’s local, timezones with a negative offset will generate timestamps in the future and timezones with positive offsets will be in the past.
The lack of timezone also makes comparing now()
and utcnow()
unpredictable. In the US/Mountain
timezone, a datetime
generated after another can report that it was generated before!
from datetime import datetime
in_the_past = datetime.utcnow()
datetime.now() < in_the_past # True
Although the Python documentation is clear that this function should be avoided, it has yet to be marked as deprecated, even in the upcoming 3.10 release. So double check your code!
By the way, if you want a unix timestamp, I recommend the succinct time.time()
:
import time
time.time() # 1623721105.8261912