我尝试编写一个接受UTC时间戳(自纪元以来的秒数)的函数,并使用tz = utc为该时间戳发出时区感知日期时间。但我遇到了一个奇怪的问题。
重现的步骤:
(a)将您的系统时区设置为非GMT。 (在这种情况下,洛杉矶。在GMT + 0000之前和之后,还测试了各种俄罗斯,中国,南美和冰岛时区。)
>>> import datetime
>>> from dateutil import tz
>>> epoch_seconds = 0
>>> dt = datetime.datetime.fromtimestamp(epoch_seconds)
>>> print(dt)
1969-12-31 16:00:00
>>> dt = dt.replace(tzinfo=tz.tzlocal())
>>> print(dt)
1969-12-31 16:00:00-08:00
>>> dt = dt.astimezone(tz=tz.tzutc())
>>> print(dt)
1970-01-01 00:00:00+00:00
>>> assert '{:%Y-%m-%d %H:%M:%S %z}'.format(dt) == '1970-01-01 00:00:00 +0000'
>>>
(b)将您的时区设置为伦敦/都柏林/等同于格林威治标准时间。
>>> import datetime
>>> from dateutil import tz
>>> epoch_seconds = 0
>>> dt = datetime.datetime.fromtimestamp(epoch_seconds)
>>> print(dt)
1970-01-01 01:00:00
>>> dt = dt.replace(tzinfo=tz.tzlocal())
>>> print(dt)
1970-01-01 01:00:00+00:00
>>> dt = dt.astimezone(tz=tz.tzutc())
>>> print(dt)
1970-01-01 01:00:00+00:00
>>> assert '{:%Y-%m-%d %H:%M:%S %z}'.format(dt) == '1970-01-01 00:00:00 +0000'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
>>>
你能帮助我理解为什么这个看似在任何非GMT时区有效但在GMT没有吗?
代码的意图是:
dt = datetime.datetime.fromtimestamp(0)
dt = dt.replace(tzinfo=tz.tzlocal())
dt = dt.astimezone(tz=tz.tzutc())
我认为问题在于dt = datetime.datetime.fromtimestamp(0)
,因为即使在那时,调用print(dt)
显示01:00作为时间而不是00:00。
更新它凌晨1点,因为英国实际上是在英国标准时间&#34; (GMT + 0100)1970年1月1日。也许dateutil的tz不知道吗?它只是当前规则的抽象表示?可能?
答案 0 :(得分:0)
我最终使用pytz
库解决了这个问题。我不认为可以使用datetime
来解决,因为datetime
的时区转换并不知道英国人在整个1970年使用GMT + 0100而不仅仅是夏天。
将系统时区设置为Europe / London:
>>> import datetime
>>> from pytz import timezone
>>> epoch_seconds = 0
>>> dt = datetime.datetime.utcfromtimestamp(epoch_seconds)
>>> print(dt)
1970-01-01 00:00:00
>>> dt = timezone('UTC').localize(dt)
>>> print(dt)
1970-01-01 00:00:00+00:00
>>> assert '{:%Y-%m-%d %H:%M:%S %z}'.format(dt) == '1970-01-01 00:00:00 +0000'
将系统时区设置为America / Los_Angeles
>>> import datetime
>>> from pytz import timezone
>>> epoch_seconds = 0
>>> dt = datetime.datetime.utcfromtimestamp(epoch_seconds)
>>> print(dt)
1970-01-01 00:00:00
>>> dt = timezone('UTC').localize(dt)
>>> print(dt)
1970-01-01 00:00:00+00:00
>>> assert '{:%Y-%m-%d %H:%M:%S %z}'.format(dt) == '1970-01-01 00:00:00 +0000'
>>>
本地时间永远不必以这种方式进入 - 你可以生成一个天真的时间戳,用pytz localize
告诉它是UTC。
答案 1 :(得分:0)
我正在尝试编写一个接受UTC时间戳(自纪元以来的秒数)的函数,并使用tz = utc
为该时间戳发出时区感知日期时间
#!/usr/bin/env python3
from datetime import datetime, timezone
aware_dt = datetime.fromtimestamp(epoch_seconds, timezone.utc)
我不认为使用datetime可以解决这个问题,因为datetime的时区转换并不知道英国人在整个1970年使用GMT + 0100而不仅仅是夏天。
如果python可以访问您系统上的tz数据库,那么它确实知道规则:
$ TZ=Europe/London ptpython
>>> from datetime import datetime, timezone
>>> epoch_seconds = 0
>>> aware_dt = datetime.fromtimestamp(epoch_seconds, timezone.utc)
>>> aware_dt
datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)
>>> aware_dt.astimezone() # local time (1am)
datetime.datetime(1970, 1, 1, 1, 0, tzinfo=datetime.timezone(datetime.timedelta(0, 3600), 'BST'))
>>> _.astimezone(timezone.utc) # back to utc
datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)
要提供对tz数据库的便携式访问,您可以使用pytz
时区,例如,通过tzlocal
模块:
>>> import tzlocal # $ pip install tzlocal
>>> datetime.fromtimestamp(epoch_seconds, tzlocal.get_localzone()) # local time (1am)
datetime.datetime(1970, 1, 1, 1, 0, tzinfo=<DstTzInfo 'Europe/London' BST+1:00:00 STD>)
btw,dateutil
也提供对tz数据库的访问权限。如果它不起作用:它是错误的用法或错误。尝试更新到最新的python-dateutil
版本,以查看问题是否消失。