Successfully reported this slideshow.
Your SlideShare is downloading. ×

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

Check these out next

1 of 42 Ad
1 of 42 Ad
Advertisement

More Related Content

Similar to Python 3.9からの新定番zoneinfoを使いこなそう (20)

Advertisement

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

  1. 1. Python 3.9からの新定番 zoneinfoを使いこなそう Ryuji Tsutsui PyCon JP 2021 発表資料 2021/10/15
  2. 2. お前誰よ • Ryuji Tsutsui@ryu22e • 普段は六本木のフィンテック系企業でDjangoを使ってWebサービスを 作っています • 関わっているコミュニティ • Python Boot Camp、Shonan.py、Python Charity Talks in Japanなど • PyCon APAC 2013、PyCon JP 2014はスタッフでした
  3. 3. 今日話すこと 1. zoneinfoの概要の説明と基本的な使い方 2. zoneinfoのよくあるエラー 3. zoneinfoの周辺知識
  4. 4. オーディエンスに求める前提知識 • Pythonチュートリアル(https://docs.python.org/ja/3/tutorial/)
 またはそれに準ずる入門書を読んで自分でPythonコードを
 書いたことがある。
  5. 5. 本の宣伝 技術評論社刊『Python実践レシピ』を執筆中 2022年1月発売予定 ページ数: 未定 金額: 未定 「Pythonライブラリ厳選レシピ」を大幅に加 筆、改訂!!!
  6. 6. 1. zoneinfoの概要の説明と基本的な 使い方
  7. 7. zoneinfoとは何か • IANAタイムゾーンデータベースを扱う機能を提供するPythonの標準
 モジュールです。 • IANAタイムゾーンデータベースとは • Internet Assigned Numbers Authority(IANA)が管理している、 世界各地のタイムゾーン情報を収めたデータベースです。 • このデータベースは、ほとんどのOSに内蔵されています。
  8. 8. • 2019年5月15日のPaul Ganssleさんによる提案が始まりでした (https://pyfound.blogspot.com/2019/05/paul-ganssle-time-zones- in-standard.html) zoneinfo誕生の経緯(1)
  9. 9. • Paul Ganssleさんの提案の要約: • 「Pythonは"batteries included"な言語のはずなのに、タイムゾーン に関する機能が足りない」 • 「IANAタイムゾーンデータベースはタイムゾーンデータの事実上の 標準で、多くのOSに内蔵されている。これを参照する標準モジュー ルを追加してはどうか。」 zoneinfo誕生の経緯(2)
  10. 10. • かくして、zoneinfoに関する
 PEP(Python Enhancement Proposals)
 PEP 615(https://www.python.org/dev/peps/pep-0615/)が作成 されました。 zoneinfo誕生の経緯(3)
  11. 11. 「タイムゾーンを扱う」と言えば • zoneinfo登場以前には、pytzというサードパーティライブラリが定番 でした。 • 次のスライドで、zoneinfoとpytzの主な違い2点についてお話ししま す。
  12. 12. pytzとの主な違い(1) • zoneinfoはOSに内蔵されているタイムゾーンデータベースを
 参照します。 • pytzはライブラリ自体にタイムゾーンデータベースが
 内蔵されています。 • pytzはタイムゾーンデータベースが更新されるとライブラリの
 アップデートが必要です。
  13. 13. pytzとの主な違い(2) • zoneinfoはPython 3.6からdatetimeモジュールに追加された
 「fold属性」に対応しています。 • pytzは「fold属性」に対応していません。 「fold属性」が何なのかについては、次の「基本的な使い方」の中で説明します。
  14. 14. 基本的な使い方 • ZoneInfoクラスの使い方 • ZoneInfoクラスをdatetimeオブジェクトと一緒に使う方法 • fold属性についての説明もします
  15. 15. 基本的な使い方(ZoneInfoクラスの使い方) >>> from zoneinfo import ZoneInfo >>> ASIA_TOKYO = ZoneInfo('Asia/Tokyo') >>> ASIA_TOKYO zoneinfo.ZoneInfo(key='Asia/Tokyo')
  16. 16. 基本的な使い方(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
  17. 17. 基本的な使い方(ZoneInfoクラスの使い方) >>> import zoneinfo >>> # 指定できる値はzoneinfo.available_timezones()で調べられ る >>> zoneinfo.available_timezones() # set型の値が返ってくる {'Asia/Seoul', 'America/Dominica',(省略), 'Asia/Tokyo', (省略), 'Asia/Pyongyang'}
  18. 18. 基本的な使い方(ZoneInfoクラスの使い方) >>> from zoneinfo import ZoneInfo >>> ZoneInfo('spam') Traceback (most recent call last): (省略) zoneinfo._common.ZoneInfoNotFoundError: 'No time zone found with key spam'
  19. 19. 基本的な使い方
 (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'))
  20. 20. 基本的な使い方
 (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'))
  21. 21. 基本的な使い方
 (datetimeオブジェクトと一緒に使う場合) • 続いて、ZoneInfoクラスとdatetimeオブジェクトのfold属性を一緒に 使う方法について説明します。 • …が、まず最初にfold属性が何なのかを説明します。
  22. 22. 公式ドキュメント「datetime.fold」の説明を引用
 https://docs.python.org/ja/3/library/datetime.html#datetime.datetime.fold [0, 1] のどちらかです。 繰り返し期間中の実時間の曖昧さ 除去に使われます。 (繰り返し期間は、夏時間の終わりに 時計が巻き戻るときや、現在のゾーンの UTC オフセット が政治的な理由で減少するときに発生します。) 0 (1) とい う値は、同じ実時間で表現される 2 つの時刻のうちの早 い方 (遅い方) を表します。
  23. 23. なるほど、わからん
  24. 24. 公式ドキュメント「datetime.fold」の説明を抜粋
 https://docs.python.org/ja/3/library/datetime.html#datetime.datetime.fold [0, 1] のどちらかです。 繰り返し期間中の実時間の曖昧さ 除去に使われます。 (繰り返し期間は、夏時間の終わりに 時計が巻き戻るときや、現在のゾーンの UTC オフセット が政治的な理由で減少するときに発生します。) 0 (1) とい う値は、同じ実時間で表現される 2 つの時刻のうちの早 い方 (遅い方) を表します。 (1)どうやら、これをどうにかするのがfold属性の機能っぽい。 (2)「繰り返し期間」が発生するタイミングがこの2つ。
 これらが手がかりになりそう。
  25. 25. 2020年 アメリカ ロサンゼルスを例にした 「夏時間の終わりに時計が巻き戻るとき」の説明 ここに注目 ①時計の針を1時間進める ②時計の針を1時間巻き戻す
  26. 26. 「時計が巻き戻るとき」に起こる問題
  27. 27. 【問題】これは標準時間? それとも夏時間? >>> 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属性はこの問題を解決してくれます。
  28. 28. 「夏時間の終わりに時計が巻き戻るとき」とは • 夏時間の終わりになると、時計が1時間巻き戻ります。 • すると、1日に同じ時刻が2度現れることになります。 • datetimeオブジェクトのfold属性は、2度現れる時刻を区別するため に使われます。 • 0なら2つの時刻のうちの早い方(つまり夏時間)、1なら遅い方 (つまり標準時間)を表します。
  29. 29. 先ほどの問題の答え >>> 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
  30. 30. 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
  31. 31. 「現在のゾーンの UTC オフセットが政治的な理 由で減少するとき」とは • 実は、夏時間以外の理由でタイムゾーンが変更されることがありま す。 • 例えば、2011年の年末にはサモア共和国でタイムゾーンが変更されま した(夏時間が理由ではなく政治的な理由で)。 • この変更で前述の「時計が巻き戻るとき」が発生する場合、1日に2度 同じ時刻が現れます。
  32. 32. タイムゾーンについてもっと詳しく
 知りたいなら • Dai MIKURUBEさんの「タイムゾーン呪いの書 (知識編)」が
 お勧めです。 • https://zenn.dev/dmikurube/articles/curse-of-timezones-common- ja
  33. 33. 2. zoneinfoのよくあるエラー
  34. 34. 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とは?
  35. 35. Windowsでzoneinfoを使う場合 $ # tzdataというCPythonのコア開発者がメンテナンスしているファーストパーティパッケージをインストール します。 $ pip install tzdata
  36. 36. なぜこんなことが起こるのか • zoneinfoでIANAデータベースを参照するにはTZifファイルが必要です。 • ところが、WindowsではTZifファイルを提供していません。その代わ り、IANAタイムゾーンデータベースを扱う独自のAPIがあります。 • タイムゾーンデータそのものを参照するAPIはありません。 • 詳細はPEP615を参照: https://www.python.org/dev/peps/pep-0615/ #windows-support-via-microsoft-s-icu-api
  37. 37. 3. zoneinfoの周辺知識
  38. 38. 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
  39. 39. Djangoのzoneinfo対応について • DjangoはUSE_TZ = Trueのときにタイムゾーンが有効になります。 • 元々はpytzのみに依存していました。 • Django 3.2(2021年10月15日時点での最新バージョン)からは従来のpytz に加えて、pytz以外のタイムゾーン実装(zoneinfoを含む)もサポートするよ うになりました。 • Django 4.0(2021年12月リリース予定)ではzoneinfoがデフォルト、pytzは 非推奨になります。
  40. 40. 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'))
  41. 41. まとめ • zoneinfoはOS内蔵のIANAタイムゾーンデータベースを参照して
 タイムゾーンを扱う標準モジュール • zoneinfoはdatetimeのfold属性にも対応している • fold属性とは、タイムゾーン変更時の「時計が巻き戻るとき」に
 起こる、1日に2度同じ時刻が現れる現象に対応した機能 • Windowsで使うときはtzdataも必要
  42. 42. ご清聴ありがとう ございました

×