Pytz 在没有 DST 的情况下将时间转换为 UTC

Posted

技术标签:

【中文标题】Pytz 在没有 DST 的情况下将时间转换为 UTC【英文标题】:Pytz convert time to UTC without DST 【发布时间】:2018-06-27 12:42:34 【问题描述】:

在发布此内容之前,我已经进行了大量研究,但我似乎无法正确转换。我有一些带有时间戳的数据,有些应用了 DST,而另一些则没有。我认为指定它没有 DST 的正确方法是使用 pytz 的 is_dst 参数。所有 3 个选项都给出了与 UTC 相同的偏移量,这是不正确的。偏移量应为 +1000。进行这种转换的最佳方法是什么,为什么 is_dst 参数没有任何区别?

pytz_eastern.localize(datetime(2018, 1, 18, 18, 50), is_dst=None).strftime('%Y-%m-%d %H:%M %z')
'2018-01-18 18:50 +1100'
pytz_eastern.localize(datetime(2018, 1, 18, 18, 50), is_dst=False).strftime('%Y-%m-%d %H:%M %z')
'2018-01-18 18:50 +1100'
pytz_eastern.localize(datetime(2018, 1, 18, 18, 50), is_dst=True).strftime('%Y-%m-%d %H:%M %z')
'2018-01-18 18:50 +1100'

【问题讨论】:

“对于大多数时间戳,is_dst 参数被忽略。它仅在 DST 转换模糊期间使用以消除这种模糊性。” pytz_eastern 的转换是什么? 夏令时从 10 月的第一个星期日开始,到 4 月的第一个星期日结束。 2017 年 10 月 1 日 - 2018 年 4 月 1 日 【参考方案1】:

对于大多数时间戳,is_dst 参数被忽略。它仅在 DST 过渡模糊期间使用以解决这种模糊性。

您试图通过忽略转换规则来转换日期时间。我认为 pytz 不会支持这一点。相反,您可以选择标准时间的日期并询问其偏移量,然后使用它。

>>> from datetime import *
>>> import pytz
>>> pytz_eastern = pytz.timezone('Australia/Sydney')

utcoffset 方法提供特定日期时间的偏移量(dst 方法也将只提供 DST 偏移量)。

>>> pytz_eastern.dst(datetime(2018, 6, 1))
datetime.timedelta(0)
>>> pytz_eastern.utcoffset(datetime(2018, 6, 1))
datetime.timedelta(0, 36000)

>>> pytz_eastern.dst(datetime(2018, 1, 1))
datetime.timedelta(0, 3600)
>>> pytz_eastern.utcoffset(datetime(2018, 1, 1))
datetime.timedelta(0, 39600)

从标准时间的日期中取出utcoffset,直接用datetime的tzinfo kwarg设置,然后才交给pytz进行转换。

所以这是显示在未针对 DST 调整的时钟上的日期时间:

>>> standard_offset = timezone(pytz_eastern.utcoffset(datetime(2018, 6, 1)))
>>> datetime(2018, 1, 18, 18, 50, tzinfo=standard_offset).strftime('%Y-%m-%d %H:%M %z')
'2018-01-18 18:50 +1000'

这也是同样的日期时间被带回现实:

>>> datetime(2018, 1, 18, 18, 50, tzinfo=standard_offset).astimezone(pytz_eastern).strftime('%Y-%m-%d %H:%M %z')
'2018-01-18 19:50 +1100'

(标准偏移量似乎也可用作._utcoffset,但没有记录,因此这是要求特定日期的 utcoffset 的原因,因为过去的偏移量不太可能改变。)

事实上,由于 pytz 为您提供了计算出的偏移量和当前 DST 值,您可以将两者相减以获得忽略 DST 的标准偏移量。

def add_forgotten_dst(dt, zoneinfo):
    '''Like pytz.localize, but ignores dst.'''
    utcoffset = zoneinfo.utcoffset(dt)
    dst = zoneinfo.dst(dt)
    standard_offset = utcoffset - dst
    dt = dt.replace(tzinfo=timezone(standard_offset))
    return dt.astimezone(zoneinfo)

>>> naive_time = datetime(2018, 1, 18, 18, 50)
>>> print(pytz_eastern.localize(naive_time))
2018-01-18 18:50:00+11:00
>>> print(add_forgotten_dst(naive_time, pytz_eastern))
2018-01-18 19:50:00+11:00

【讨论】:

非常感谢,这是一个很好的解决方案,并且确实帮助我了解了正在发生的事情。 该功能运行良好。我也在函数内部添加了 zoneinfo,所以我需要做的就是传递 datetime 参数。 当我运行代码时,我得到standard_offset = timezone(ro.utcoffset(datetime(2018, 6, 1))) File "/usr/lib/python3/dist-packages/pytz/__init__.py", line 157, in timezone if zone.upper() == 'UTC': AttributeError: 'datetime.timedelta' object has no attribute 'upper' 错误。这是为什么呢?

以上是关于Pytz 在没有 DST 的情况下将时间转换为 UTC的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 3 的 Pytz 模块中将 EST、CST 和 DST 时区转换为 unix 时间戳

在没有 DST 的情况下将时间保存为 UTC(时刻)

使用 pytz 时区时 Python 日期时间不包括 DST

如何在不使用不安全代码的情况下将float转换为二进制?

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

如何在没有副本的情况下将结构转换为字节数组?