はじめに
Pythonでdatetime型を少しリッチに使おうと思ったら、pendulumが便利。
pendulumを用いて文字列からdatetime型を生成する時、 pendulum.parse
を用いる。
この時、RFC3339やISO8601フォーマットである日時の文字列の他に、
2012-01-01
といった日付文字列や、 00:00
時間情報の文字列でもdatetime型を生成することができる。
>>> import pendulum
>>> pendulum.parse("2012-01-01")
DateTime(2012, 1, 1, 0, 0, 0, tzinfo=Timezone('UTC'))
>>> pendulum.parse("00:00")
DateTime(2024, 2, 6, 0, 0, 0, tzinfo=Timezone('UTC'))
問題
pendulum.parse("18:00", tz='Asia/Tokyo')
と書くと、「実行時点のAsia/Tokyoタイムゾーン日付の18:00のdatetime型」 を生成すると思っていたが、違うみたい。
実際には、 「実行時点のUTCタイムゾーン日付の18:00のdatetime型」 を返す。
例えば、実行時点が2024/02/02 03:00の場合、
# 期待する値
>>> pendulum.parse("18:00", tz='Asia/Tokyo')
DateTime(2024, 2, 2, 18, 0, 0, tzinfo=Timezone('Asia/Tokyo'))
# 実際の値
>>> pendulum.parse("18:00", tz='Asia/Tokyo')
DateTime(2024, 2, 1, 18, 0, 0, tzinfo=Timezone('Asia/Tokyo'))
期待していた値よりも1日ずれてしまう。
解決方法
では、「実行時点のAsia/Tokyoの日付で、時間情報のみを上書きしたDatetime型」 を生成したい場合どうしたらいいのか?
>>> import pendulum
>>> from datetime import datetime
>>> timezone = pendulum.timezone('Asia/Tokyo')
>>> today = pendulum.today(timezone)
>>> target_time = pendulum.parse("18:00", exact=True)
>>> datetime.combine(today, target_time)
datetime.datetime(2024, 2, 6, 18, 0)
exact=True
にすることで、Time型が生成できるので、それを結合する。
(もっといい書き方がある気がする...?)
You can pass the exact keyword argument to parse() to get the exact type that the string represents:
おわりに
実行時点に依存する処理のバグは発見が難しい...
あと余談だが、 pendulum.parse
の引数はチェックが甘いのでtypoにも気をつけたい。
# ↓が普通に実行できる
target_time = pendulum.parse("18:00", hogehoge="fugafuga")
参考