python – 使用pytz从UTC偏移“Canonical”?

我很好奇如何调用在某些时区选择器上提供的“规范”时区偏移(如果甚至有这样的事情,作为规范偏移,我甚至不确定).

例如,在Windows XP上,您可以看到对于东部时间(美国和加拿大),下拉列表始终显示GMT-05:00这实际上在全年都不正确,因为当夏令时生效时, UTC的偏移量仅为-4:00.另一方面,每个人都提到美国/东方距离UTC 5小时.我想知道如何调用-5:00.电子邮件时间标识符?典型的时区偏移?

另外,如果我用pytz创建美国/东部时区,有没有办法抓住-5:00而不管现在的实际时间是否在夏令时?我的意思是……我想知道是否有一个功能,或者……得到-5:00的东西,无论我今天或8月中旬运行(当DST启用时和实际偏差仅为-4:00)

图片来自http://www.microsoft.com/library/media/1033/windowsxp/images/using/setup/tips/67446-change-time-zone.gif

先感谢您.

最佳答案 如果我们将“规范”表示不在DST中的日期的utcoffset,则问题将减少为查找不是DST的日期(对于每个时区).

我们可以先尝试当前日期.如果不是DST,那么我们很幸运.如果是,那么我们可以单步执行utc转换日期列表(存储在tzone._utc_transition_times中),直到我们找到一个不是DST的日期:

import pytz
import datetime as DT
utcnow = DT.datetime.utcnow()

canonical = dict()
for name in pytz.all_timezones:
    tzone = pytz.timezone(name)
    try:
        dstoffset = tzone.dst(utcnow, is_dst=False)
    except TypeError:
        # pytz.utc.dst does not have a is_dst keyword argument
        dstoffset = tzone.dst(utcnow)
    if dstoffset == DT.timedelta(0):
        # utcnow happens to be in a non-DST period
        canonical[name] = tzone.localize(utcnow, is_dst=False).strftime('%z') 
    else:
        # step through the transition times until we find a non-DST datetime
        for transition in tzone._utc_transition_times[::-1]:
            dstoffset = tzone.dst(transition, is_dst=False) 
            if dstoffset == DT.timedelta(0):
                canonical[name] = (tzone.localize(transition, is_dst=False)
                                   .strftime('%z'))
                break

for name, utcoffset in canonical.iteritems():
    print('{} --> {}'.format(name, utcoffset)) 

# All timezones have been accounted for
assert len(canonical) == len(pytz.all_timezones)

产量

...
Mexico/BajaNorte --> -0800
Africa/Kigali --> +0200
Brazil/West --> -0400
America/Grand_Turk --> -0400
Mexico/BajaSur --> -0700
Canada/Central --> -0600
Africa/Lagos --> +0100
GMT-0 --> +0000
Europe/Sofia --> +0200
Singapore --> +0800
Africa/Tripoli --> +0200
America/Anchorage --> -0900
Pacific/Nauru --> +1200

请注意,上面的代码访问私有属性tzone._utc_transition_times.这是pytz中的实现细节.由于它不是公共API的一部分,因此不保证在未来版本的pytz中存在.实际上,在当前版本的pytz中,它甚至不存在于所有时区中 – 特别是,对于没有DST转换时间的时区,例如“非洲/布琼布拉”,它不存在. (这就是我为什么要先检查utcnow是否恰好在非DST时间段内的原因.)

如果你想要一种不依赖私有属性的方法,我们可以简单地将utcnow返回到有一天,直到我们找到一个非DST时间段的日子.代码会比上面的代码慢一点,但是因为你真的只需要运行一次这段代码来收集所需的信息,所以它真的无关紧要.

以下是不使用_utc_transition_times的代码:

import pytz
import datetime as DT
utcnow = DT.datetime.utcnow()

canonical = dict()
for name in pytz.all_timezones:
    tzone = pytz.timezone(name)
    try:
        dstoffset = tzone.dst(utcnow, is_dst=False)
    except TypeError:
        # pytz.utc.dst does not have a is_dst keyword argument
        dstoffset = tzone.dst(utcnow)
    if dstoffset == DT.timedelta(0):
        # utcnow happens to be in a non-DST period
        canonical[name] = tzone.localize(utcnow, is_dst=False).strftime('%z') 
    else:
        # step through the transition times until we find a non-DST datetime
        date = utcnow
        while True:
            date = date - DT.timedelta(days=1)
            dstoffset = tzone.dst(date, is_dst=False) 
            if dstoffset == DT.timedelta(0):
                canonical[name] = (tzone.localize(date, is_dst=False)
                                   .strftime('%z'))
                break

for name, utcoffset in canonical.iteritems():
    print('{} --> {}'.format(name, utcoffset)) 

# All timezones have been accounted for
assert len(canonical) == len(pytz.all_timezones)
点赞