微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Python 3.9:使用标准库构造DST有效时间戳

如何解决Python 3.9:使用标准库构造DST有效时间戳


我只想使用Python 3.9中的标准库来构造DST有效的时间戳,并希望此版本可以实现。

在我的时区“欧洲/柏林”中,2020年的DST过境点是:
2020-03-29 02:00时钟切换到03:00(没有2小时!)
2020-10-25 03:00时钟切换回02:00(小时2存在两次!)

我的脚本产生以下输出
3月
2020-03-29 01:59:00 + 01:00 CET加1小时:2020-03-29 02:59:00 + 01:00 CET
(应该是CEST的03:59:00,因为没有2小时!)

十月
2020-10-25 02:00:00 + 02:00 CEST加上1小时:2020-10-25 03:00:00 + 01:00 CET
(似乎可以-编辑:应为欧洲中部时间02:00 !!)

下面提供了示例代码。 Windows用户可能需要“ pip install tzdata”才能正常工作。

任何建议将不胜感激!

'''
Should work out of the Box with Python 3.9

Got a fallback import statement.

BACKPORT (3.6+)
pip install backports.zoneinfo

WINDOWS (TM) needs:
pip install tzdata
'''

from datetime import datetime,timedelta
from time import tzname
try:
    from zoneinfo import ZoneInfo
except ImportError:
    from backports import zoneinfo
    ZoneInfo = zoneinfo.ZoneInfo


tz = ZoneInfo("Europe/Berlin")
hour = timedelta(hours=1)

print("marcH")
dt_01 = datetime(2020,3,29,1,59,tzinfo=tz)

dt_02 = dt_01 + hour
print(f"{dt_01} {dt_01.tzname()} plus 1 h: {dt_02} {dt_02.tzname()}")


print("\nOCTOBER")
dt_01 = datetime(2020,10,25,2,tzinfo=tz)
dt_02 = dt_01 + hour
print(f"{dt_01} {dt_01.tzname()} plus 1 h: {dt_02} {dt_02.tzname()}")

解决方法

尽管这是违反直觉的,但这是预期的。有关日期时间算术如何工作的更多详细信息,请参见this blog post。这样做的原因是,在timedelta上添加datetime应该被认为是“将日历/时钟提前X倍”,而不是“日历/时钟在这段时间后会说什么”已经过去”。请注意,第一个问题可能导致的时间甚至不在当地时区!

如果需要,“ datetime代表什么时间timedelta代表的时间过去了?” (看起来确实可以做到),您应该做一些等同于转换为UTC并返回的操作,例如:

from datetime import datetime,timedelta,timezone

def absolute_add(dt: datetime,td: timedelta) -> datetime:
    utc_in = dt.astimezone(timezone.utc)  # Convert input to UTC
    utc_out = utc_in + td  # Do addition in UTC
    civil_out = utc_out.astimezone(dt.tzinfo)  # Back to original tzinfo
    return civil_out

我相信您可以创建一个覆盖timedelta的{​​{1}}子类来为您执行此操作(如果可以的话,我想将类似的东西引入标准库中)。>

请注意,如果__add__dt.tzinfo,这将使用您的系统本地时区来确定如何进行绝对加法,并且它将返回一个已知时区。在None中运行它:

America/New_York

如果您希望对原始日期时间进行民用加法,对已知日期时间进行绝对加法,则可以在函数中检查它是否天真:

>>> absolute_add(datetime(2020,11,1,1),timedelta(hours=1))
datetime.datetime(2020,tzinfo=datetime.timezone(datetime.timedelta(days=-1,seconds=68400),'EST'))

此外,要明确一点,这与def absolute_add_nolocal(dt: datetime,td: timedelta) -> datetime: if dt.tzinfo is None: return dt + td return absolute_add(dt,td) 无关。这一直是Python中日期时间的语义,这不是我们可以向后兼容的方式进行更改的方式。 zoneinfo的工作方式略有不同,因为添加知道pytz的日期时间是错误的事情,并且在算术发生后需要执行pytz步骤,normalize作者决定pytz应该使用绝对时间语义。

normalize还可以与absolute_addpytz一起使用,因为它使用的操作对于所有时区库都适用。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。