为啥萨摩亚的 pytz 和 dateutil 得到不同的结果?

Posted

技术标签:

【中文标题】为啥萨摩亚的 pytz 和 dateutil 得到不同的结果?【英文标题】:Why do I get different results for pytz and dateutil for Samoa?为什么萨摩亚的 pytz 和 dateutil 得到不同的结果? 【发布时间】:2019-02-07 18:10:06 【问题描述】:

我原以为以下两个会给出相同的结果,但事实并非如此。为什么会这样?

版本:

pytz==2018.5
python-dateutil==2.7.3

示例 1:pytz

import datetime
import pytz

tz = pytz.timezone('Pacific/Apia')
today_utc = datetime.datetime(2011, 12, 30, 9, 59,
                              tzinfo=datetime.timezone.utc)
today_tz = today_utc.astimezone(tz)
print(today_tz.isoformat())

打印2011-12-29T23:59:00-10:00(正确)

示例 2:dateutil

import datetime
import dateutil.tz

tz = dateutil.tz.gettz('Pacific/Apia')
today_utc = datetime.datetime(2011, 12, 30, 9, 59,
                              tzinfo=datetime.timezone.utc)
today_tz = today_utc.astimezone(tz)
print(today_tz.isoformat())

打印2011-12-29T23:59:00+14:00(这是错误的)

【问题讨论】:

为什么说-10是对的,+14是不对的? This page 说 Pacific/Apia 通常是 UTC+13,而 DST 是 UTC+14。 因为 2011-12-29 是-10。他们改变了时区。见timeanddate.de/stadt/zeitzone/samoa/apia lol 没想到...所以,您期望 dateutil 应该能够根据日期更改时区。也许它根本不这样做。 @zvone 所有偏移量取决于日期 @zvone 好吧,可能是这样。但我想从某人那里听到/在这里获得参考。目前,我假设我只是以错误的方式使用 dateutil 。如果它不能处理同一时区内的偏移量变化(我之前措辞很糟糕),那就太糟糕了。它经常发生。 【参考方案1】:

你发现了一个bug in dateutil,我现在已经报告了它和fixed。

该错误是由 dateutil 中如何计算转换的“墙壁时间”的问题引起的,当时区的基本偏移量在 DST 期间发生变化时,该假设不成立。稍微扩展您的示例:

from datetime import datetime, timedelta
from dateutil import tz
import pytz

APIA = tz.gettz('Pacific/Apia')
APIA_p = pytz.timezone('Pacific/Apia')
dt0 = datetime.fromisoformat('2011-12-29T20:00-10:00')

for i in range(5):
    dt = (dt0 + timedelta(hours=i))
    dt_d = dt.astimezone(APIA)
    dt_p = dt.astimezone(APIA_p)
    print(f'dt_d.isoformat(), dt_p.isoformat()')

## Result:
# 2011-12-29T20:00:00-10:00, 2011-12-29T20:00:00-10:00
# 2011-12-29T21:00:00-10:00, 2011-12-29T21:00:00-10:00
# 2011-12-29T22:00:00-10:00, 2011-12-29T22:00:00-10:00
# 2011-12-29T23:00:00+14:00, 2011-12-29T23:00:00-10:00
# 2011-12-31T00:00:00+14:00, 2011-12-31T00:00:00+14:00

您可以看到dateutil 总是正确计算日期和时间,但是当isoformat 调用utcoffset 时,偏移量会提前1 小时发生变化。这是因为astimezone 在后台调用tzinfo.fromutc,而isoformat 调用utcoffsetdateutil 以 UTC 和本地时间存储转换时间,fromutc 使用 UTC 时间,utcoffsetdsttzname 使用本地时间。此错误涉及在计算 DST->DST 转换期间转换的“墙壁时间”时过度补偿 DST(这非常罕见),这就是它不影响 astimezone 的原因。

底线 - 您正确使用了 pytzdateutil,此错误将在下一个版本中修复。

注意:这个答案是在我找到错误的原因并修复后编辑的。

【讨论】:

以上是关于为啥萨摩亚的 pytz 和 dateutil 得到不同的结果?的主要内容,如果未能解决你的问题,请参考以下文章

使用pytz时,为什么不是萨摩亚+13或+14的偏移量?

为啥 pytz 似乎没有任何时区信息?

为啥 pytz 在跨越 TZ 和 DST 边界而不是 TZ 名称时正确调整时间和偏移量?

pytz:为啥在时区之间转换时需要规范化?

为啥我会得到欧洲/柏林时区 0:53 的偏移量?

为啥我得到欧洲/柏林时区的偏移量 0:53?