问题
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