python: utcfromtimestamp vs fromtimestamp, when the timestamp is based on utcnow()

不羁的心 提交于 2020-06-16 03:16:12

问题


Pretty sure it's an easy one but I don't get it.

My local TZ is currently GMT+3, and when I take timestamp from datetime.utcnow().timestamp() it is indeed giving me 3 hours less than datetime.now().timestamp()

During another process in my flow, I take that utc timestamp and need to turn it into datetime.

When I'm doing fromtimestamp I get the right utc hour, but when I'm using utcfromtimestamp I get another 3 hours offset.

The documentation, though, asks me to use fromtimestamp for local timezone, and utcfromtimestamp for utc usages.

What am I missing ? is the initial assumption for both funcs is that the timestamp is given in local timezone ?

Thank you :)


回答1:


The key thing to notice when working with datetime objects and their POSIX timestamps at the same time is that naive datetime objects (the ones without timezone information) are assumed by Python to refer to local time (OS setting). In contrast, a POSIX timestamp (should) always refer to UTC seconds since the epoch. You can unambiguously obtain it by time.time(). In your example, not-so-obvious things happen:

1) datetime.now().timestamp() - now() gives you a naive datetime object that resembles local time. If you call for the timestamp(), Python converts the datetime to UTC and calculates the timestamp for that.

2) datetime.utcnow().timestamp() - utcnow() gives you a naive datetime object that resembles UTC. However, if you call timestamp(), Python assumes (since naive) that the datetime is local time - and converts to UTC again before calculating the timestamp! The resulting timestamp is therefore off from UTC by twice your local time's UTC offset...

A code example. Let's make some timestamps. Note that I'm on UTC+2, so offset is -7200 s.

import time
from datetime import datetime, timezone

ts_ref = time.time() # reference POSIX timestamp

ts_utcnow = datetime.utcnow().timestamp() # dt obj UTC but naive - so also assumed local

ts_now = datetime.now().timestamp() # dt obj naive, assumed local

ts_loc_utc = datetime.now(tz=timezone.utc).timestamp() # dt obj localized to UTC

print(int(ts_utcnow - ts_ref))
# -7200 # -> ts_utcnow doesn't refer to UTC!
print(int(ts_now - ts_ref))
# 0 # -> correct
print(int(ts_loc_utc - ts_ref))
# 0 # -> correct

I hope this clarifies that if you do datetime.utcfromtimestamp(ts_utcnow), you get double the local time's UTC offset. Python assumes (which I think is pretty sane) that the timestamp refers to UTC - which in fact, it does not.

My suggestion would be to use timezone-aware datetime objects; like datetime.now(tz=timezone.utc). The dateutil library can also be very helpful when working with datetime and timezones. And if you want to dig deep, have a look at the datetime src code. That could also help clarifying the issue you encountered.



来源:https://stackoverflow.com/questions/62286398/python-utcfromtimestamp-vs-fromtimestamp-when-the-timestamp-is-based-on-utcnow

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!