2018/11/30

[Python] datetime のコンストラクタでタイムゾーンは指定しない方がよい

以下を見てください。 日本のタイムゾーンが +9:19 になってしまいました。

1
2
3
>>> import datetime, pytz
>>> datetime.datetime(2018, 9, 1, tzinfo=pytz.timezone('Asia/Tokyo'))
datetime.datetime(2018, 9, 1, 0, 0, tzinfo=<dsttzinfo 'asia="" tokyo'="" lmt+9:19:00="" std="">)

調べてみると、pytz 2017.2 以降を使う場合、上記のような動作になるようです。

原因については、以下のコメント欄が参考になります。(以下の記事で触れているのは replace でタイムゾーン指定した場合ですが、コンストラクタで指定した場合も同様)

参考

pytzの仕様が変わっている - Qiita

簡単に言うと、「複数のタイムゾーン(UTC オフセット)を持つエリアでは、日付が決まらないとオフセットが決定できないので、 勝手にデフォルトのオフセットが採用される」ということのようです。

一般的に「複数のタイムゾーンを持つエリア」といえば、サマータイムがあるようなエリアで、日本は当てはまらない気がします。 ところが、日本は 1887年以前は今とは異なるタイムゾーン (+09:18:591) だったそうです。

参考

一行入魂 PostgreSQLのtime zoneについて

pytz 2017.2 以降はこれを厳密に守るようになったということみたいですね2

というわけで、aware な datetime オブジェクトを作成するには、 一度 native で作成してから aware に変換するのが正しいやり方のようです。

1
2
3
4
>>> import datetime, pytz
>>> dt = datetime.datetime(2018, 9, 1)
>>> pytz.timezone('Asia/Tokyo').localize(dt)
datetime.datetime(2018, 9, 1, 0, 0, tzinfo=<dsttzinfo 'asia="" tokyo'="" jst+9:00:00="" std="">)

今回、たまたま日本のタイムゾーンで問題が起こって調べましたが、他のタイムゾーン3では同じ問題が前からあったということですね4

  1. 9:19:00 ではない。pytz は秒まで持てないからね… 
  2. とはいえ、100年以上前のタイムゾーンがデフォルトってどうなのよ?と思いますが… 
  3. サマータイムがあるなど 
  4. 多分。確認はしていないけど。 
?

0 件のコメント: