如何在 CEST 和 UTC 时区之间转换日期时间对象

Pet*_*ood 5 python timezone datetime dst

我不想使用该pytz库,因为我正在处理的项目需要文书工作来引入依赖项。如果我可以在没有第三方库的情况下实现这一点,我会更开心。

当日期处于夏令时时,我无法在 CET 和 UTC 之间转换日期。这与我期望的不同一个小时:

>>> print from_cet_to_utc(year=2017, month=7, day=24, hour=10, minute=30)
2017-07-24T09:30Z

2017-07-24T08:30Z  # expected
Run Code Online (Sandbox Code Playgroud)

CET 比 UTC 早 1 小时,夏季比 UTC 早 2 小时。因此,我预计仲夏的中欧 10:30 实际上是 UTC 时间 8:30。

功能是:

from datetime import datetime, tzinfo, timedelta

def from_cet_to_utc(year, month, day, hour, minute):
    cet = datetime(year, month, day, hour, minute, tzinfo=CET())
    utc = cet.astimezone(tz=UTC())
    return '{:%Y-%m-%d:T%H:%MZ}'.format(utc)
Run Code Online (Sandbox Code Playgroud)

我使用两个时区信息对象:

class CET(tzinfo):
    def utcoffset(self, dt):
        return timedelta(hours=1)

    def dst(self, dt):
        return timedelta(hours=2)

class UTC(tzinfo):
    def utcoffset(self, dt):
        return timedelta(0)

    def dst(self, dt):
        return timedelta(0)
Run Code Online (Sandbox Code Playgroud)

小智 8

只是补充@Sergey 的答案

要知道何时应该应用夏令时,您应该获取夏令时开始和结束的日期/时间的历史数据,并检查是否必须应用到指定的datetime。您可以从IANA 数据库中获取这些信息,也可以在许多在线资源中进行查询,例如timeanddate 网站

另一个细节是CET是一个不明确的名称,因为它被多个时区使用。实际时区名称使用IANA 数据库定义的名称Region/City(始终采用Europe/Paris或等格式Europe/Berlin)。


间隙和重叠

我将使用Europe/Berlin时区作为示例。今年(2017 年),柏林的夏令时于 3 月 26 日开始凌晨 2 点,时钟向前移动 1 小时至凌晨 3 点,偏移量从+01:00变为+02:00

您还可以认为时钟直接从凌晨 1:59 跳转到凌晨 3 点,这意味着凌晨 2 点到凌晨 2:59 之间的所有当地时间在当天的那个时区都​​不存在。这称为间隙,您应该检查这种情况(一种常见的方法是将凌晨 2 点调整为下一个有效时间 - 在本例中为夏令时凌晨 3 点)。

在同一时区,2017 年夏令时将于 10 月 29 日结束凌晨 3 点,时钟将向后拨1 小时至凌晨 2 点,偏移量将从+02:00变为+01:00

这意味着凌晨 2 点到凌晨 2:59 之间的所有当地时间将出现两次:一次在 DST ( +02:00) 中,一次在非 DST ( +01:00) 中。这称为重叠,在创建datetime属于这种情况的重叠时,您必须决定选择创建哪一个(应该是夏令时凌晨 2 点还是非夏令时偏移?由您决定!)。


PS:现在每个使用 CET 的欧洲国家都在不同的年份采用了它,所以如果您正在处理旧日期,您也必须考虑这一点。

另一个细节是 DST 是由政府定义的,并且不能保证规则将永远如此,并且您必须相应地更新规则 - 使用 的另一个优点pytz,因为它的更新是从 IANA 版本生成并发布在PyPI(感谢@Matt Johnson指出此信息)。

您确定文书工作比手工编写这些规则更糟糕吗?只要检查一下如何读取 IANA tz 文件,也许您就会改变主意。

  • 只是为了回答您关于 pytz 更新的观点,它们是从 IANA 版本生成的。IANA 2017b => pytz 2017.2。Stuart Bishop 维护它们,并将它们发布到 pypi:https://pypi.python.org/pypi/pytz#downloads (2认同)