目次

pytz

since 2018-08-11

Python で日付や時刻(タイムゾーンなど)を扱うために pytz がよく使われる。

http://pytz.sourceforge.net/

夏時間が終わるときに1日に2回同じローカルタイムが存在する。

それを区別するために is_dst がある。

from datetime import datetime
import pytz
e = pytz.timezone('US/Eastern')
dt = datetime(2018,11,4, 1,30,0)
print(e.localize(dt, is_dst=True).astimezone(pytz.utc))
# 2018-11-04 05:30:00+00:00
print(e.localize(dt, is_dst=False).astimezone(pytz.utc))
# 2018-11-04 06:30:00+00:00

引数を省略すると False と扱われるが None を明示的に指定すると例外になる。

e.localize(dt, is_dst=None)
# => AmbiguousTimeError: 2018-11-04 01:30:00

django.utils.timezone の make_aware 関数の説明に出てくる

pandas の Timestamp.tz_localize

日本の1951年の夏時間も扱えている。やはり夏時間が終わるときにひとつのローカル時刻が2つのUTC時刻に対応する。

https://www.timeanddate.com/time/change/japan/tokyo?year=1951

j = pytz.timezone('Asia/Tokyo')
dt = datetime(1951,9,8, 1,30,0)
print(j.localize(dt, is_dst=True).astimezone(pytz.utc))
# 1951-09-07 15:30:00+00:00
print(j.localize(dt, is_dst=False).astimezone(pytz.utc))
# 1951-09-07 16:30:00+00:00

タイムゾーンは地域だけで決まらない。

現在の pytz では timezone('Asia/Tokyo') はデフォルトのオフセットが9時間19分になっている。

このへんが由来か

https://github.com/stub42/pytz/blob/master/tz/asia#L1512

バグではなく「仕様の厳格化」という話。

https://gist.github.com/a-hisame/85ed049d622f5a88c570c252f6611ff0

jst = pytz.timezone('Asia/Tokyo')
print(jst.utcoffset)
# <bound method DstTzInfo.utcoffset of <DstTzInfo 'Asia/Tokyo' LMT+9:19:00 STD>>
t1 = datetime(2018,8,11, 9,0,0, tzinfo=jst)
print(t1)
# 2018-08-10 23:41:00+00:00
print(pytz.utc.normalize(t1))
# 2018-08-10 23:41:00+00:00

timezone インスタンスを特定の時刻でローカライズする、という手順で正しく変換できる。

t2 = datetime(2018,8,11, 9,0,0)
print(jst.localize(t2))
# 2018-08-11 09:00:00+09:00
print(jst.localize(t2).astimezone(pytz.utc))
# 2018-08-11 00:00:00+00:00