GAE/Pyでの日付型

Google App Engineで現在の日付時刻を取得するとUTC時刻が返ってくる。
しかもこの日付にはタイムゾーン情報が入ってない。

from datetime import datetime

now = datetime.now()
now.strftime('%Y/%m/%d %H:%M:%S%z')
# '2011/04/03 15:01:22'
# ↑実際の日本時間より9時間前の時刻
# タイムゾーンなし


dateutilとかを使ってタイムゾーンを指定してあげれば、日本時間を取得することができる。

from datetime import datetime
from dateutil.tz

jst = dateutil.tz.gettz('Asia/Tokyo')
now = datetime.now(jst)
now.strftime('%Y/%m/%d %H:%M:%S%z')
# '2011/04/04 00:05:49+0900'


kay frameworkを使ってるとこんな感じ。

from datetime import datetime
from kay.utils

jst = kay.utils.get_timezone(settings.DEFAULT_TIMEZONE)
now = datetime.now(jst)
now.strftime('%Y/%m/%d %H:%M:%S%z')
# '2011/04/04 00:11:13+0900'

データストアにはタイムゾーン情報を保存できない

上ので日本時間での現在時刻を取得することはできたけど、これをデータストアに保存するとタイムゾーン情報が消えてしまう。
正確に言うと、タイムゾーン情報がついた日時データは、UTC時刻に変換された上で、タイムゾーン情報のない状態で保存される。

now = datetime.now(jst))
ishida = Person(updated = now)
# '2011/04/04 00:11:13+0900'
# 日本時間。タイムゾーンあり。

ishida.put()
ishida = Person.get_by_id(1)
ishida.updated
# '2011/04/03 15:11:13'
# UTC。タイムゾーンなし。


日本時間とUTCが混在するとプログラムはとてもややこしくなる。同じUTCでもタイムゾーンを持つ日付と持たない日付が混在したりするともう手が付けられない。
例えば、タイムゾーンありの日付とタイムゾーンなしの日付は比較することができない。比較しようとすると以下のエラーが発生する。

can't compare offset-naive and offset-aware datetimes

ややこしさを減らすために統一する

日付型の変数が日本時間なのかUTCなのか、タイムゾーンを持ってるか持ってないかを意識してプログラミングしないといけないのだけど、そんなことをしていると複雑度が増して不幸になるので、統一してシンプルにする方向で考えた方がよい。

データストアがタイムゾーンなしのUTCを主張しているので、もうこれには逆らわない方がよい。データストアに保存する日付はタイムゾーンなしのUTCに統一する。そうするとプログラム中で扱う日付は全てタイムゾーンなしUTCに統一できる。

入出力の境界で変換する

統一できるといってもユーザーが入力する日付や、外部から取得したフィードの日付などは日本時間だったりタイムゾーンがついていたりする。
これらは実際の処理に渡す前にタイムゾーンなしのUTCに変換する必要がある。日本時間やタイムゾーンつきの日付を本来の処理に持ち込ませないよう、入力を受け付ける水際で全て変換する。
同様に、ユーザーに時刻を表示する際も、本来の処理が終わった後に日本時間に変換する。