Why does this
datetime not have any timezone info given that it is explicitly a UTC
I would expect that this would contain
UTC dates don’t need any timezone info since they’re UTC, which by definition means that they have no offset.
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
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.
That means it is timezone naive, so you can’t use it with
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
To get the current time in a given timezone, you could pass tzinfo to
#!/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.
pytz module is one option, and there is another
python-dateutil, which although is also third party package, may already be available depending on your other dependencies and operating system.
I just wanted to include this methodology for reference- if you’ve already installed
python-dateutil for other purposes, you can use its
tzinfo instead of duplicating with
import datetime import dateutil.tz # Get the UTC time with datetime.now: utcdt = datetime.datetime.now(dateutil.tz.tzutc()) # Get the UTC time with datetime.utcnow: utcdt = datetime.datetime.utcnow() utcdt = utcdt.replace(tzinfo=dateutil.tz.tzutc()) # For fun- get the local time localdt = datetime.datetime.now(dateutil.tz.tzlocal())
I tend to agree that calls to
utcnow should include the UTC timezone information. I suspect that this is not included because the native datetime library defaults to naive datetimes for cross compatibility.
datetime.utcnow() doesn’t set
tzinfo to indicate that it is UTC, but
datetime.now(datetime.timezone.utc) does return UTC time with
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)
from datetime import datetime from dateutil.relativedelta import relativedelta d = datetime.now() date = datetime.isoformat(d).split('.') d_month = datetime.today() + relativedelta(months=1) next_month = datetime.isoformat(d_month).split('.')
Julien Danjou wrote a good article explaining why you should never deal with timezones. An excerpt:
Indeed, Python datetime API always returns unaware datetime objects,
which is very unfortunate. Indeed, as soon as you get one of this
object, there is no way to know what the timezone is, therefore these
objects are pretty “useless” on their own.
Alas, even though you may use
utcnow(), you still won’t see the timezone info, as you discovered.
Always use aware
datetimeobjects, i.e. with timezone information. That
makes sure you can compare them directly (aware and unaware
objects are not comparable) and will return them correctly to users.
Leverage pytz to have timezone objects.
Use ISO 8601 as the input and
output string format. Use
timestamps as string formatted using that format, which includes the
If you need to parse strings containing ISO 8601 formatted timestamps,
you can rely on
iso8601, which returns timestamps with correct
timezone information. This makes timestamps directly comparable.
timezone information in Python 3.2+
import datetime >>> d = datetime.datetime.now(tz=datetime.timezone.utc) >>> print(d.tzinfo) 'UTC+00:00'
The behaviour of
datetime.datetime.utcnow() returning UTC time as naive datetime object is obviously problematic and must be fixed. It can lead to unexpected result if your system local timezone is not UTC, since datetime library presume naive datetime object to represent system local time. For example,
datetime.datetime.utcnow().timestaamp() gives timestamp of 4 hours ahead from correct value on my computer. Also, as of python 3.6,
datetime.astimezone() can be called on naive datetime instances, but
datetime.datetime.utcnow().astimezone(any_timezone) gives wrong result unless your system local timezone is UTC.
It should include and
now() also. Related issue.
So till that,
now() is preferred over
from datetime import datetime, timezone utc = timezone.utc date = datetime.now(utc) print(date) # 2022-04-06 05:40:13.025347+00:00