classification
Title: Possible bug in datetime utc
Type: behavior Stage:
Components: Library (Lib) Versions: Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: cryvate, gabhcosta, primal, tim.peters, veky
Priority: normal Keywords:

Created on 2021-07-17 21:20 by gabhcosta, last changed 2021-07-20 13:31 by petr.viktorin.

Messages (6)
msg397733 - (view) Author: Gabriel Costa (gabhcosta) Date: 2021-07-17 21:20
>>> datetime.now(timezone.utc).timestamp()
1626556067.054988
>>> datetime.utcnow().timestamp()
1626566875.174921

Should there be a difference between the two modes?
msg397734 - (view) Author: Henk-Jaap Wagenaar (cryvate) * Date: 2021-07-17 22:29
I don't seem to be able to reproduce this by running this one-liner:

from datetime import datetime, timezone; print(datetime.now(timezone.utc).timestamp()); print(datetime.u
tcnow().timestamp());

on 3.9.5. How did you achieve this? It looks like the difference one would expect from (fast) human input).
msg397736 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2021-07-17 23:41
> It looks like the difference one would expect from (fast) human input)

Nope, the timestamps in the original report are about 3 hours apart (10808+ seconds).

Reports like these are often much clearer if they state the timezone of the system they're running on.

Plausible here: as the docs say, `utcnow()` returns a _naive_ datetime - no timezone info is attached.

But `.timestamp()`:

"""
Naive datetime instances are assumed to represent local time 
"""

So I _expect_ the results to differ unless the box this is running on uses UTC as its local time.

On my box, in native timezone CDT, the two ways are 5 hours apart, which is indeed CDT's offset from UTC.
msg397740 - (view) Author: Vedran Čačić (veky) * Date: 2021-07-18 05:34
Would it be possible to change .utcnow to now return a datetime annotated with UTC "timezone"? After all, now we have timezone-aware datetimes and the convention that naive means local, this behavior might even be considered a bug.
msg397753 - (view) Author: Paul Martin (primal) * Date: 2021-07-18 15:11
The difference between the two is the difference between your local time and utc.

datetime.now(timezone.utc)

This returns the current time in utc and is timezone aware. So the timestamp can figure out the seconds since epoch taking into account the timezone.


datetime.utcnow()

Returns the current utc time but is not timezone aware. When timestamp  method is run, it is interpreted as a local timestamp.

This is explained in the docs but perhaps it should be made clearer that
datetime.utcnow().timestamp() is incorrect and would cause bugs. 

I'm not sure about changing the behaviour of utcnow to return a timezone-aware dt as is it could cause hard to detect bugs in existing code. But I did have issues recently where I was using utcnow until I went back and read the docs and changed to datetime.now(timezone.utc). So it's probably a common trap to fall into.

From the docs:

"
Naive datetime instances are assumed to represent local time #

Note There is no method to obtain the POSIX timestamp directly from a naive datetime instance representing UTC time. If your application uses this convention and your system timezone is not set to UTC, you can obtain the POSIX timestamp by supplying tzinfo=timezone.utc:
timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
or by calculating the timestamp directly:

timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)"


Warning Because naive datetime objects are treated by many datetime methods as local times, it is preferred to use aware datetimes to represent times in UTC. As such, the recommended way to create an object representing the current time in UTC is by calling datetime.now(timezone.utc).
"
msg397769 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2021-07-19 00:16
If you want to pursue changing what utcnow() does, python-ideas or python-dev would probably need to be involved. Backward-incompatible changes are very hard sells.

As Paul Ganssle noted here,

https://blog.ganssle.io/articles/2019/11/utcnow.html

in Python 2, naïve datetimes generally did _not_ get treated as "being in local time", ever. They refused to pretend they had any opinion about time zone, and operations like .timestamp() (just "like", because .timestamp() didn't exist in Python 2) raised an exception when applied to a naïve datetime.

Which, IMO, Python 3 should have stuck with. "Naïve time" was never intended to be a synonym for "local time" - or for UTC time - or for any other timezone-aware notion of time.

But as Paul also said, if Python 2 had concrete tzinfo classes to begin with, it's a pretty safe bet `utcnow()` would never have existed.
History
Date User Action Args
2021-07-20 13:31:15petr.viktorinsetcomponents: + Library (Lib), - C API
2021-07-19 00:16:00tim.peterssetmessages: + msg397769
2021-07-18 15:11:48primalsetnosy: + primal
messages: + msg397753
2021-07-18 05:34:16vekysetnosy: + veky
messages: + msg397740
2021-07-17 23:41:41tim.peterssetnosy: + tim.peters
messages: + msg397736
2021-07-17 22:29:23cryvatesetnosy: + cryvate
messages: + msg397734
2021-07-17 21:20:17gabhcostacreate