python-3.x - python 3.9 : Construct DST valid timestamp using standard library

标签 python-3.x timezone dst timedelta zoneinfo

我想仅使用 Python 3.9 中的标准库构建 DST 有效时间戳,并希望此版本可以实现。在我的时区“欧洲/柏林”中,2020 年的 DST 交叉点是:
2020-03-29 在 02:00 时钟切换到 03:00(没有小时 2!)
2020-10-25 在 03:00 时钟切换回 02:00(小时 2 存在两次!)
我的脚本产生以下输出:
行进
2020-03-29 01:59:00+01:00 CET 加 1 小时:2020-03-29 02:59:00+01:00 CET
(应该是 03:59:00 CEST 因为没有小时 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, 0, 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有关日期时间算法如何工作的更多详细信息。这样做的原因是添加了一个 timedeltadatetime应该被认为是“将日历/时钟提前 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覆盖 __add__ 的子类为你做这件事(如果可以的话,我想向标准库介绍这样的东西)。
请注意,如果 dt.tzinfoNone ,这将使用您的系统本地时区来确定如何进行绝对加法,并返回一个可感知的时区。在 America/New_York 中运行它:
>>> absolute_add(datetime(2020, 11, 1, 1), timedelta(hours=1))
datetime.datetime(2020, 11, 1, 1, 0, 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)
另外,要明确的是,这与 zoneinfo 无关。 .这一直是 Python 中日期时间的语义,我们无法以向后兼容的方式更改它。 pytz确实有点不同,因为添加 pytz -aware datetimes 做错了事,需要 normalize算术发生后的步骤,以及 pytz作者决定normalize应该使用绝对时间语义。absolute_add也适用于 pytzdateutil ,因为它使用适用于所有时区库的操作。

关于python-3.x - python 3.9 : Construct DST valid timestamp using standard library,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64440016/

相关文章:

postgresql - 在 PostgreSQL 中正确处理 TIME WITH TIME ZONE

Python - 从 DST 调整的本地时间到 UTC

python-3.x - 平滑图像的锯齿状边缘

python - 如何从列表中随机选择一个元组?

python 从字典中获取唯一值

python - 如何对 Pyramid 中的 request.json_body 进行单元测试?

java - 如何获取指定 ISO 国家代码的时区 ID?

java - UTC Unix 时间戳存储在错误时区的 Java 程序中的 HSQLDB 中

python - 更改joined_at时区discord.py

python - 将 unixtime 转换为 datetime 对象并再次返回(时间转换函数对)