Why does datetime.datetime.utcnow() not contain timezone information?

PythonDatetime

Python Problem Overview


datetime.datetime.utcnow()

Why does this datetime not have any timezone info given that it is explicitly a UTC datetime?

I would expect that this would contain tzinfo.

Python Solutions


Solution 1 - Python

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)

Solution 2 - Python

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.

Solution 3 - Python

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.

Solution 4 - Python

The 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 pytz

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.

Solution 5 - Python

To add timezone information in Python 3.2+

import datetime

>>> d = datetime.datetime.now(tz=datetime.timezone.utc)
>>> print(d.tzinfo)
'UTC+00:00'

Solution 6 - Python

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.

Recommendations:

> * Always use aware datetime objects, i.e. with timezone information. That > makes sure you can compare them directly (aware and unaware datetime > 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 datetime.datetime.isoformat() to return > timestamps as string formatted using that format, which includes the > timezone information. > > * 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.

Solution 7 - Python

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.

Solution 8 - Python

It should include and now() also. Related issue.

So till that, now() is preferred over today() and utcnow().

from datetime import datetime, timezone
utc = timezone.utc
date = datetime.now(utc)
print(date) # 2022-04-06 05:40:13.025347+00:00

Solution 9 - Python

from datetime import datetime 
from dateutil.relativedelta import relativedelta
d = datetime.now()
date = datetime.isoformat(d).split('.')[0]
d_month = datetime.today() + relativedelta(months=1)
next_month = datetime.isoformat(d_month).split('.')[0]

Solution 10 - Python

UTC dates don't need any timezone info since they're UTC, which by definition means that they have no offset.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVitaly BabiyView Question on Stackoverflow
Solution 1 - PythonCraig McQueenView Answer on Stackoverflow
Solution 2 - PythonJohn La RooyView Answer on Stackoverflow
Solution 3 - PythonMark RansomView Answer on Stackoverflow
Solution 4 - PythonbbengfortView Answer on Stackoverflow
Solution 5 - PythonnordbornView Answer on Stackoverflow
Solution 6 - PythonJoe D'AndreaView Answer on Stackoverflow
Solution 7 - PythonHansol ShinView Answer on Stackoverflow
Solution 8 - PythonSmart ManojView Answer on Stackoverflow
Solution 9 - PythonMrudula AthuluriView Answer on Stackoverflow
Solution 10 - PythonIgnacio Vazquez-AbramsView Answer on Stackoverflow