KEMBAR78
Python 3.9からの新定番zoneinfoを使いこなそう | PDF
Python 3.9からの新定番
zoneinfoを使いこなそう
Ryuji Tsutsui
PyCon JP 2021 発表資料
2021/10/15
お前誰よ
• Ryuji Tsutsui@ryu22e
• 普段は六本木のフィンテック系企業でDjangoを使ってWebサービスを
作っています
• 関わっているコミュニティ
• Python Boot Camp、Shonan.py、Python Charity Talks in Japanなど
• PyCon APAC 2013、PyCon JP 2014はスタッフでした
今日話すこと
1. zoneinfoの概要の説明と基本的な使い方
2. zoneinfoのよくあるエラー
3. zoneinfoの周辺知識
オーディエンスに求める前提知識
• Pythonチュートリアル(https://docs.python.org/ja/3/tutorial/)

またはそれに準ずる入門書を読んで自分でPythonコードを

書いたことがある。
本の宣伝
技術評論社刊『Python実践レシピ』を執筆中
2022年1月発売予定
ページ数: 未定
金額: 未定
「Pythonライブラリ厳選レシピ」を大幅に加
筆、改訂!!!
1. zoneinfoの概要の説明と基本的な
使い方
zoneinfoとは何か
• IANAタイムゾーンデータベースを扱う機能を提供するPythonの標準

モジュールです。
• IANAタイムゾーンデータベースとは
• Internet Assigned Numbers Authority(IANA)が管理している、
世界各地のタイムゾーン情報を収めたデータベースです。
• このデータベースは、ほとんどのOSに内蔵されています。
• 2019年5月15日のPaul Ganssleさんによる提案が始まりでした
(https://pyfound.blogspot.com/2019/05/paul-ganssle-time-zones-
in-standard.html)
zoneinfo誕生の経緯(1)
• Paul Ganssleさんの提案の要約:
• 「Pythonは"batteries included"な言語のはずなのに、タイムゾーン
に関する機能が足りない」
• 「IANAタイムゾーンデータベースはタイムゾーンデータの事実上の
標準で、多くのOSに内蔵されている。これを参照する標準モジュー
ルを追加してはどうか。」
zoneinfo誕生の経緯(2)
• かくして、zoneinfoに関する

PEP(Python Enhancement Proposals)

PEP 615(https://www.python.org/dev/peps/pep-0615/)が作成
されました。
zoneinfo誕生の経緯(3)
「タイムゾーンを扱う」と言えば
• zoneinfo登場以前には、pytzというサードパーティライブラリが定番
でした。
• 次のスライドで、zoneinfoとpytzの主な違い2点についてお話ししま
す。
pytzとの主な違い(1)
• zoneinfoはOSに内蔵されているタイムゾーンデータベースを

参照します。
• pytzはライブラリ自体にタイムゾーンデータベースが

内蔵されています。
• pytzはタイムゾーンデータベースが更新されるとライブラリの

アップデートが必要です。
pytzとの主な違い(2)
• zoneinfoはPython 3.6からdatetimeモジュールに追加された

「fold属性」に対応しています。
• pytzは「fold属性」に対応していません。
「fold属性」が何なのかについては、次の「基本的な使い方」の中で説明します。
基本的な使い方
• ZoneInfoクラスの使い方
• ZoneInfoクラスをdatetimeオブジェクトと一緒に使う方法
• fold属性についての説明もします
基本的な使い方(ZoneInfoクラスの使い方)
>>> from zoneinfo import ZoneInfo
>>> ASIA_TOKYO = ZoneInfo('Asia/Tokyo')
>>> ASIA_TOKYO
zoneinfo.ZoneInfo(key='Asia/Tokyo')
基本的な使い方(ZoneInfoクラスの使い方)
>>> from zoneinfo import ZoneInfo
>>> # オブジェクトはタイムゾーン名ごとにキャッシュされる
>>> ZoneInfo('Asia/Tokyo') is ZoneInfo('Asia/Tokyo')
True
>>> ZoneInfo('America/Los_Angeles') is 
... ZoneInfo('America/Los_Angeles')
True
>>> ZoneInfo('America/Los_Angeles') is 
... ZoneInfo('Asia/Tokyo')
False
基本的な使い方(ZoneInfoクラスの使い方)
>>> import zoneinfo
>>> # 指定できる値はzoneinfo.available_timezones()で調べられ
る
>>> zoneinfo.available_timezones() # set型の値が返ってくる
{'Asia/Seoul', 'America/Dominica',(省略), 'Asia/Tokyo',
(省略), 'Asia/Pyongyang'}
基本的な使い方(ZoneInfoクラスの使い方)
>>> from zoneinfo import ZoneInfo
>>> ZoneInfo('spam')
Traceback (most recent call last):
(省略)
zoneinfo._common.ZoneInfoNotFoundError: 'No time
zone found with key spam'
基本的な使い方

(datetimeオブジェクトと一緒に使う場合)
>>> from zoneinfo import ZoneInfo
>>> from datetime import datetime
>>> ASIA_TOKYO = ZoneInfo('Asia/Tokyo')
>>> dt = datetime(2021, 2, 23, 10, tzinfo=ASIA_TOKYO)
# 日本時刻で2021年2月23日10:00のdatetimeオブジェクトを作成
>>> dt
datetime.datetime(2021, 2, 23, 10, 0,
tzinfo=zoneinfo.ZoneInfo(key='Asia/Tokyo'))
基本的な使い方

(datetimeオブジェクトと一緒に使う場合)
>>> # (前のスライドのコードの続き)
>>> # 日本時刻2021年2月23日10:00をアメリカのロサンゼルスの日時に
変換
>>> dt.astimezone(ZoneInfo('America/Los_Angeles'))
datetime.datetime(2021, 2, 22, 17, 0,
tzinfo=zoneinfo.ZoneInfo(key='America/Los_Angeles'))
基本的な使い方

(datetimeオブジェクトと一緒に使う場合)
• 続いて、ZoneInfoクラスとdatetimeオブジェクトのfold属性を一緒に
使う方法について説明します。
• …が、まず最初にfold属性が何なのかを説明します。
公式ドキュメント「datetime.fold」の説明を引用

https://docs.python.org/ja/3/library/datetime.html#datetime.datetime.fold
[0, 1] のどちらかです。 繰り返し期間中の実時間の曖昧さ
除去に使われます。 (繰り返し期間は、夏時間の終わりに
時計が巻き戻るときや、現在のゾーンの UTC オフセット
が政治的な理由で減少するときに発生します。) 0 (1) とい
う値は、同じ実時間で表現される 2 つの時刻のうちの早
い方 (遅い方) を表します。
なるほど、わからん
公式ドキュメント「datetime.fold」の説明を抜粋

https://docs.python.org/ja/3/library/datetime.html#datetime.datetime.fold
[0, 1] のどちらかです。 繰り返し期間中の実時間の曖昧さ
除去に使われます。 (繰り返し期間は、夏時間の終わりに
時計が巻き戻るときや、現在のゾーンの UTC オフセット
が政治的な理由で減少するときに発生します。) 0 (1) とい
う値は、同じ実時間で表現される 2 つの時刻のうちの早
い方 (遅い方) を表します。
(1)どうやら、これをどうにかするのがfold属性の機能っぽい。
(2)「繰り返し期間」が発生するタイミングがこの2つ。

これらが手がかりになりそう。
2020年 アメリカ ロサンゼルスを例にした
「夏時間の終わりに時計が巻き戻るとき」の説明
ここに注目
①時計の針を1時間進める
②時計の針を1時間巻き戻す
「時計が巻き戻るとき」に起こる問題
【問題】これは標準時間? それとも夏時間?
>>> from zoneinfo import ZoneInfo
>>> from datetime import datetime
>>> # アメリカ ロサンゼルスの2020-11-01 1:00
>>> dt = datetime(2020, 11, 1, 1, tzinfo=ZoneInfo('America/Los_Angeles'))
>>> print(dt) # 標準時間(UTC+8:00)? それとも夏時間(UTC+7:00)?
fold属性はこの問題を解決してくれます。
「夏時間の終わりに時計が巻き戻るとき」とは
• 夏時間の終わりになると、時計が1時間巻き戻ります。
• すると、1日に同じ時刻が2度現れることになります。
• datetimeオブジェクトのfold属性は、2度現れる時刻を区別するため
に使われます。
• 0なら2つの時刻のうちの早い方(つまり夏時間)、1なら遅い方
(つまり標準時間)を表します。
先ほどの問題の答え
>>> from zoneinfo import ZoneInfo
>>> from datetime import datetime
>>> dt = datetime(2020, 11, 1, 1, tzinfo=ZoneInfo('America/Los_Angeles'))
>>> print(dt) # デフォルトはfold=0、つまり夏時間(UTC+7:00)
2020-11-01 01:00:00-07:00
>>> print(dt.replace(fold=1)) # fold=1の時は標準時間(UTC+8:00)
2020-11-01 01:00:00-08:00
pytzはdatetimeのfold属性に対応していない
>>> from pytz import timezone
>>> from datetime import datetime
>>> LOS_ANGELES = timezone('America/Los_Angeles')
>>> dt = LOS_ANGELES.localize(datetime(2020, 11, 1, 1))
>>> print(dt) # fold=0の時は遷移前のオフセット
2020-11-01 01:00:00-08:00
>>> print(dt.replace(fold=1)) # fold=0の時と結果が変わっていない
2020-11-01 01:00:00-08:00
「現在のゾーンの UTC オフセットが政治的な理
由で減少するとき」とは
• 実は、夏時間以外の理由でタイムゾーンが変更されることがありま
す。
• 例えば、2011年の年末にはサモア共和国でタイムゾーンが変更されま
した(夏時間が理由ではなく政治的な理由で)。
• この変更で前述の「時計が巻き戻るとき」が発生する場合、1日に2度
同じ時刻が現れます。
タイムゾーンについてもっと詳しく

知りたいなら
• Dai MIKURUBEさんの「タイムゾーン呪いの書 (知識編)」が

お勧めです。
• https://zenn.dev/dmikurube/articles/curse-of-timezones-common-
ja
2. zoneinfoのよくあるエラー
Windowsでzoneinfoを使う場合
>>> from zoneinfo import ZoneInfo
>>> ASIA_TOKYO = ZoneInfo('Asia/Tokyo') # Asia/Tokyoは存在するはずなのに…
Traceback (most recent call last):
(省略)
ModuleNotFoundError: No module named 'tzdata'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:Users****AppDataLocalProgramsPythonPython39libzoneinfo_common.py", line 24, in load_tzdata
raise ZoneInfoNotFoundError(f"No time zone found with key {key}")
zoneinfo._common.ZoneInfoNotFoundError: 'No time zone found with key Asia/Tokyo'
tzdataとは?
Windowsでzoneinfoを使う場合
$ # tzdataというCPythonのコア開発者がメンテナンスしているファーストパーティパッケージをインストール
します。
$ pip install tzdata
なぜこんなことが起こるのか
• zoneinfoでIANAデータベースを参照するにはTZifファイルが必要です。
• ところが、WindowsではTZifファイルを提供していません。その代わ
り、IANAタイムゾーンデータベースを扱う独自のAPIがあります。
• タイムゾーンデータそのものを参照するAPIはありません。
• 詳細はPEP615を参照: https://www.python.org/dev/peps/pep-0615/
#windows-support-via-microsoft-s-icu-api
3. zoneinfoの周辺知識
Python 3.8以下でfold属性を扱う場合
>>> from dateutil.tz import gettz
>>> from datetime import datetime
>>> dt = datetime(2020, 11, 1, 1, tzinfo=gettz('America/Los_Angeles'))
>>> print(dt) # fold=0の時は遷移前のオフセット
2020-11-01 01:00:00-07:00
>>> print(dt.replace(fold=1)) # fold=1の時は遷移後のオフセット
2020-11-01 01:00:00-08:00
Djangoのzoneinfo対応について
• DjangoはUSE_TZ = Trueのときにタイムゾーンが有効になります。
• 元々はpytzのみに依存していました。
• Django 3.2(2021年10月15日時点での最新バージョン)からは従来のpytz
に加えて、pytz以外のタイムゾーン実装(zoneinfoを含む)もサポートするよ
うになりました。
• Django 4.0(2021年12月リリース予定)ではzoneinfoがデフォルト、pytzは
非推奨になります。
Djangoでzoneinfoを使うには
>>> from zoneinfo import ZoneInfo
>>> from django.utils import timezone
>>> # timezoneという引数がある関数にZoneInfoオブジェクトを渡し
ます。
>>> timezone.localtime(timezone=ZoneInfo('Asia/Tokyo'))
datetime.datetime(2021, 9, 7, 22, 12, 43, 952260,
tzinfo=zoneinfo.ZoneInfo(key='Asia/Tokyo'))
まとめ
• zoneinfoはOS内蔵のIANAタイムゾーンデータベースを参照して

タイムゾーンを扱う標準モジュール
• zoneinfoはdatetimeのfold属性にも対応している
• fold属性とは、タイムゾーン変更時の「時計が巻き戻るとき」に

起こる、1日に2度同じ時刻が現れる現象に対応した機能
• Windowsで使うときはtzdataも必要
ご清聴ありがとう
ございました

Python 3.9からの新定番zoneinfoを使いこなそう