Если мы под «каноническим» подразумеваем utcoffset дат, которые не находятся в DST, то проблема сводится к поиску дат (для каждого часового пояса), которые не являются 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 — в частности, он не существует для часовых поясов, в которых нет времени перехода на летнее время, таких как, например, 'Africa/Bujumbura'
. (Вот почему я сначала потрудился проверить, не находится ли 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)
person
unutbu
schedule
15.12.2014