Why does datetime.datetime.utcnow() not contain timezone information?
The standard Python libraries didn't include any tzinfo classes until Python 3.2. I can only guess at the reasons. Personally I think it was a mistake not to include a tzinfo class for UTC, because that one is uncontroversial enough to have a standard implementation. Although there was no implementation in the library, there is one given as an example in the tzinfo
documentation.
from datetime import timedelta, tzinfo
ZERO = timedelta(0)
# A UTC class.
class UTC(tzinfo):
"""UTC"""
def utcoffset(self, dt):
return ZERO
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return ZERO
utc = UTC()
Once you have a UTC tzinfo
object, you still can't use it with utcnow
. To get the current time as an aware datetime object:
from datetime import datetime
now = datetime.now(utc)
In Python 3.2 they finally put a UTC tzinfo
class in the library:
from datetime import datetime, timezone
now = datetime.now(timezone.utc)
In Python 3.9 they created tzinfo
classes for all the other time zones. See PEP 615 -- Support for the IANA Time Zone Database in the Standard Library for all the details.
Note that for Python 3.2 onwards, the datetime
module contains datetime.timezone
. The documentation for datetime.utcnow()
says:
An aware current UTC datetime can be obtained by calling
datetime.now
(
timezone.utc
)
.
So, datetime.utcnow()
doesn't set tzinfo
to indicate that it is UTC, but datetime.now(datetime.timezone.utc)
does return UTC time with tzinfo
set.
So you can do:
>>> import datetime
>>> datetime.datetime.now(datetime.timezone.utc)
datetime.datetime(2014, 7, 10, 2, 43, 55, 230107, tzinfo=datetime.timezone.utc)
That means it is timezone naive, so you can't use it with datetime.astimezone
you can give it a timezone like this
import pytz # 3rd party: $ pip install pytz
u = datetime.utcnow()
u = u.replace(tzinfo=pytz.utc) #NOTE: it works only with a fixed utc offset
now you can change timezones
print(u.astimezone(pytz.timezone("America/New_York")))
To get the current time in a given timezone, you could pass tzinfo to datetime.now()
directly:
#!/usr/bin/env python
from datetime import datetime
import pytz # $ pip install pytz
print(datetime.now(pytz.timezone("America/New_York")))
It works for any timezone including those that observe daylight saving time (DST) i.e., it works for timezones that may have different utc offsets at different times (non-fixed utc offset). Don't use tz.localize(datetime.now())
-- it may fail during end-of-DST transition when the local time is ambiguous.