446
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.

FObersteiner
  • 22,500
  • 8
  • 42
  • 72
Vitaly Babiy
  • 6,114
  • 4
  • 26
  • 24
  • How to convert a normal iso format date field which is of type string to utc format? – Navi May 28 '20 at 10:40

10 Answers10

335

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)
Craig McQueen
  • 41,871
  • 30
  • 130
  • 181
  • 3
    Which is prefered? `datetime.now(timezone.utc)` or `datetime.utcnow(timezone.utc)`? – Jesse Webb Nov 10 '14 at 20:18
  • 16
    `datetime.utcnow()` takes no arguments. So it would have to be `datetime.now(timezone.utc)`. – Craig McQueen Nov 10 '14 at 22:37
  • 1
    `datetime.now()` will return the machine time but `datetime.utcnow()` will return the actual UTC time. – Babu Jun 13 '16 at 08:08
  • 25
    @Babu: `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. – Craig McQueen Jun 13 '16 at 23:25
  • @CraigMcQueen So if we pass a `tz` object in the now constructor it will return time of that timezone? Ok! Thanks for pointing out. – Babu Jun 14 '16 at 05:50
  • 3
    I think this is the proper solution now, one shouldn't need to add an external dependency to specify the timezone metadata when it's already explicitly UTC – Jacopofar Jun 13 '19 at 12:57
  • 1
    Never use `datetime.utcnow()`. It doesn't set `tzinfo` though it is utc, but naive datetime object is presumed to represent system local time by datetime library. If your system local time is not UTC, `datetime.datetime.utcnow().astimezone(datetime.timezone.utc)` gives wrong result. – Hansol Shin Sep 16 '20 at 07:31
  • This answer should be the accepted one – Mitchell Currie Nov 30 '22 at 21:39
  • 2
    Didn't answer the question - why does it not contain timezone information? – bcb Jan 30 '23 at 02:30
  • @BB. the question is unanswerable as asked. But this answers the question *behind* the question - how do you get a `datetime` object in UTC with the proper `tzinfo` attached? – Mark Ransom Jul 19 '23 at 21:39
247

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.

jfs
  • 399,953
  • 195
  • 994
  • 1,670
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • 294
    But there's no good reason for it to be timezone naive - it's specified to be UTC. Why do you need to search out a third party library to make it work properly? – Mark Ransom Feb 25 '10 at 04:51
  • I think it may have been a licensing thing, so pytz can't be included in the stdlib – John La Rooy Feb 25 '10 at 04:53
  • 8
    I agree; for me ‘naïve’ times are completely useless. There is discussion on the python list at the moment about adding pytz to the stdlib; the issue is not licensing but the fact that the timezone data is updated so often (which Python itself can't be). Also pytz doesn't implement the tzinfo interface in the expected way so you can get errors if you try to use some of the city timezones in `astimezone`. So datetime not only has no native timezones, but the only widely-available implementation of tzinfo is non-compliant to the supposed standard. – bobince Feb 25 '10 at 16:41
  • 5
    @bobince Why don't pytz and the standard datetime libraries work for you? The Python core and pytz evolving as independent projects reduces logistical complexity for the core team. Yes, reducing the complexity for the Python core team increases the complexity for all of the Python users who need to deal with timezones but, I trust they made this decision for a good reason. The rule "The standard library has no tzinfo instances..." is great because it's simple, why make an exception here? – Derek Litz Apr 05 '13 at 17:23
  • 19
    How about just `u=datetime.now(pytz.utc)` – Craig McQueen Jul 10 '14 at 01:41
  • @bobince The lack of tzinfo in the standard library is surely a problem, but I don't see how writing your own code as a solution it's easier, faster, or better than using the pytz library which is the de-facto standard in the python world. – LeartS Dec 10 '14 at 10:23
  • I use datetime/pytz in some projects (eg where interacting with Django), but I find it very inconvenient. You invariably end up with a mixture of naïve times, UTC times, local times, local DST times, and other-server-local-times (eg DB). The result is confusion and bugs. It was ultimately a mistake to try to shoehorn fundamentally different models (an abstract calendar point, an absolute universal moment, and a combination of both) into the same datatype. I much prefer dealing with only a timestamp for data, combined with regional formatting/parsing. – bobince Dec 10 '14 at 12:20
  • `tzinfo=` does not work with pytz for DST timezones, see [this answer](http://stackoverflow.com/questions/2171189/python-tz-am-i-wrong-or-its-a-bug#2171624). – bain Jun 13 '15 at 21:00
  • 5
    @bain: don't use `tz.localize(datetime.now())`; use `datetime.now(tz)` instead. – jfs Jun 15 '15 at 07:09
  • @J.F Is that always correct? [pytz](http://pytz.sourceforge.net/) "This library differs from the documented Python API for tzinfo implementations; if you want to create local wallclock times you need to use the localize() method documented in this document." - the docs do not make clear when it is safe to ignore that rule, perhaps it is always safe for datetime.now (?) but in general passing a pytz timezone to a datetime is risky e.g. `datetime(2015, 1, 1, tzinfo=pytz.timezone('Europe/Paris'))` – bain Jun 15 '15 at 14:31
  • @bain: `now(tz)` is always correct. We are not discussing anything else here. – jfs Jun 15 '15 at 18:42
  • If I have to guess why utcnow() does not include tzinfo, it's probably because of [leap seconds](https://en.wikipedia.org/wiki/Leap_second). In other words, even UTC is subject to change. If utcnow() included a tzinfo, there are bound to be naïve programmers who don't realize that even the utc tzinfo needs to be updated from time to time, and then they run into time-related bugs and would still scratch their heads. – Kal Jun 16 '15 at 10:45
  • @J.F Author of pytz says `now(tz)` [is not always correct](https://bugs.launchpad.net/pytz/+bug/1319939/comments/12): 'even "datetime.now(pytz.timezone('Australia/Melbourne'))" could give you a timestamp out by one hour if you were unlucky and the DST transition occurred while that statement was being run.' – bain Jun 16 '15 at 18:15
  • @bain: it just proves that even the pytz author can be wrong. I've seen the code. `now(tz)` that calls `tz.fromutc` internally works even during DST transitions (because there is no DST transitions in utc). If you think I'm wrong; provide specific example (date, timezone, python, pytz version) – jfs Jun 16 '15 at 18:28
  • A long time later from the original answer, but a relatively safe localize way built into pytz: `pytz.utc.localize(datetime.utcnow())`. I've found this also incorporates the DST variations without issue. – runfaj Jul 01 '17 at 20:52
  • 2
    In 3.9+ python added the [ZoneInfo](https://docs.python.org/3/library/zoneinfo.html) class which can be used as `ZoneInfo('America/Denver')` and not use a 3rd party lib. Note that if the operating system doesn't have the zone files available it will fall back to `tzdata` from pypi (you'd need to install it). See [PEP615](https://www.python.org/dev/peps/pep-0615/) – nerdwaller Feb 02 '21 at 04:14
84

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.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 10
    Go figure as to why this class was not provided in the first place (and, more importantly, used for `datetime` objects created by `utcnow()`)... – André Caron Feb 06 '13 at 21:46
  • 5
    @rgove, that's the kind of righting of wrongs that was supposed to be fair game for Python 3. They shouldn't have worried about the backward compatibility. There's another example I read within the last few days - the `struct` module would do automatic conversions from Unicode to bytestring, and the final decision was to break compatibility with earlier Python 3 versions to prevent a bad decision from going forward. – Mark Ransom Jun 24 '13 at 19:26
  • 2
    I'm dumbfounded that Python's `tzinfo` documentation includes examples of code to implement it, but they don't include that functionality in datetime itself! https://docs.python.org/2/library/datetime.html#datetime.tzinfo.fromutc – Mr. Lance E Sloan Sep 01 '16 at 22:18
  • Also, the example UTC class shown here is almost exactly what the `pytz` module's implementation contains. It adds a few helpful methods. – Mr. Lance E Sloan Sep 01 '16 at 22:33
  • 1
    @LS yes, `pytz` is a great resource. By the time I had edited my answer to put in the example code, somebody else had already suggested it and I didn't want to steal their thunder. – Mark Ransom Sep 01 '16 at 22:51
  • This is the right answer. For backward compatibility, `utcnow()` is kept as it is. – Smart Manoj Apr 06 '22 at 04:59
21

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.

Ian Lee
  • 502
  • 1
  • 5
  • 12
bbengfort
  • 5,254
  • 4
  • 44
  • 57
  • 1
    NameError: name 'dt' is not defined – xApple Jul 23 '14 at 11:45
  • I was using the datetime.datetime.utcfromtimestamp() call, and needing to add tzinfo, The second solution worked for me: `utcdt = datetime.datetime.utcfromtimestamp(1234567890).replace(dateutil.tz.tzutc())` – Ian Lee Jan 27 '15 at 19:41
  • 1
    note: unlike `datetime.now(pytz_tz)` that always works; [`datetime.now(dateutil.tz.tzlocal())` may fail during DST transitions](https://github.com/dateutil/dateutil/issues/57). [PEP 495 -- Local Time Disambiguation](https://www.python.org/dev/peps/pep-0495/) might improve `dateutil` situation in the future. – jfs Sep 09 '15 at 12:45
  • @IanLee: you could use `utc_dt = datetime.fromtimestamp(1234567890, dateutil.tz.tzutc())` (note: [`dateutil` with a non-fixed utc offset (such as `dateutil.tz.tzlocal()`) may fail here](http://stackoverflow.com/a/17365806/4279), use [a `pytz`-based solution instead](http://stackoverflow.com/a/12692910/4279)). – jfs Sep 09 '15 at 13:23
  • Since my program was already importing `dateutil` for `dateutil.parser`, I liked this solution best. It was as simple as: `utcCurrentTime = datetime.datetime.now(tz=dateutil.tz.tzutc())`. Viola!! – Mr. Lance E Sloan Sep 01 '16 at 23:19
  • Thanks, @IanLee. The part that still puzzles me is that a method called utcfromtimestamp, which takes a POSIX timestamp as a parameter, which by definition is UTC, still produces a naïve datetime. It seems like a plain oversight to me. – Michael Scheper Oct 13 '16 at 21:12
16

To add timezone information in Python 3.2+

import datetime

>>> d = datetime.datetime.now(tz=datetime.timezone.utc)
>>> print(d.tzinfo)
'UTC+00:00'
dtasev
  • 540
  • 6
  • 12
nordborn
  • 457
  • 4
  • 4
  • 1
    ```AttributeError: 'module' object has no attribute 'timezone' ``` Python 2.7.13 (default, Jan 19 2017, 14:48:08) – Marcin Owsiany Nov 28 '17 at 11:44
  • @MarcinOwsiany try: `from datetime import datetime, timezone` then invoke with `datetime.now(tz=timezone.utc)` – s2t2 Aug 15 '20 at 18:44
  • This is the best way to get UTC timezone aware datetime object without using any third party python module like **pytz**. | Just to add one more thing. If you want to get LOCAL timezone aware datetime object without using any extra module then just add astimezone(): **d.astimezone()** – Saurav Kumar Sep 18 '20 at 14:05
11

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.

Joe D'Andrea
  • 5,141
  • 6
  • 49
  • 67
  • 3
    This is slightly misleading recommendation. The rule of thumb is, never deal with timezones. Always store and transmit tz unware utc objects (epoch objects). Timezone should be only calculated at the time of representation in UI – nehem Apr 03 '17 at 01:00
  • 1
    That sounds like it already matches up with Julien's thoughts quite well. Which of his specific recommendations (as referenced above) are misleading? – Joe D'Andrea Apr 03 '17 at 12:44
  • 1
    TZ unaware objects are not a problem if all datetime math is done in UTC. You should store and process all datetime in UTC and only convert datetime value to a specific TZ for a human when requested (i.e. at the UI layer). – cowbert May 17 '23 at 08:36
4

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.

Hansol Shin
  • 157
  • 1
  • 4
  • those of us using `datetime.datetime.utcnow()` since it was ever introduced into Python aren't using tz-aware objects in most cases anyway - we're only ever storing and processing UTC and only doing the conversion for human users at the UI level. If you want UTC with tzinfo for some reason, only stick to the modern datetime objects that have tz support. – cowbert May 17 '23 at 08:40
2

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
Smart Manoj
  • 5,230
  • 4
  • 34
  • 59
-6
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]
adamdunson
  • 2,635
  • 1
  • 23
  • 27
-15

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

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • 13
    As far as I can tell from http://docs.python.org/library/datetime.html, a datetime without a tzinfo is one where the time zone is unspecified. Here the time zone *has* been specified, so logically it should be present. There's a big difference between a date/time without an associated time zone and one which is definitely in UTC. (Ideally they should be different types IMO, but that's another matter...) – Jon Skeet Feb 25 '10 at 17:55
  • 2
    @JonSkeet I think you're missing Ignacio's point that UTC isn't a timezone. Amazing that this answer has -9 score as I type this... – C S Jan 04 '16 at 14:22
  • 6
    @CS: Well Ignacio never stated that... and while strictly speaking UTC isn't a time zone, it's usually *treated* as one to make lives considerably simpler (including in Python, e.g. with `pytz.utc`). Note that there's a big difference between a value whose offset from UTC is unknown and one where it is known to be 0. The latter is what `utcnow()` *should* return, IMO. That would fit in with "An aware object is used to represent a specific moment in time that is not open to interpretation" as per the documentation. – Jon Skeet Jan 04 '16 at 14:28