Python
AWS
サーバー
Python3
Bluemix

Pythonのdatetimeモジュールを使った時に、タイムゾーンを固定させる方法


TL;DR

タイムゾーンに関するインスタンスを引数としてかませるといいよ。

サーバーがどこにあろうと同じ時間を指してくれる。

import datetime

JST = datetime.timezone(datetime.timedelta(hours=9), "JST")

print(f"ただいま、世界協定時刻で {datetime.datetime.now(datetime.timezone.utc)} です")
# ただいま、世界協定時刻で 2018-12-31 14:03:05.436561+00:00 です
print(f"ただいま、日本時刻で {datetime.datetime.now(JST)} です")
# ただいま、日本時刻で 2018-12-31 23:03:05.436561+09:00 です


悩む

個人的にwebアプリケーションを作成したけれど、費用をできるだけ抑えるためにデプロイ先をIBM BlueMixにした。

時刻を使用して、一定時刻になったら動作する…といったプログラムを書いたのだけれど、サーバーがアメリカにあるせいで、設定した時刻の9時間後に動作してしまう。

この対処法として、datetimeオブジェクトにtimezoneを与えてあげるといいということを思い出した。


つまり

datetime.timezoneインスタンスを作成して、それをdatetimeオブジェクトの引数tzinfoとして与える

日本は世界協定時刻から見て9時間進んでいるので、9時間進んでいる設定にしてあげる

import datetime

JST = datetime.timezone(datetime.timedelta(hours=9), "JST")

第一引数には世界協定時刻からの時間差を示す-datetime.timedelta(hours=24)からdatetime.timedelta(hours=24)の間のdatetime.timedeltaオブジェクトを与え、第二引数には名前を与える。

それを以下の様にdatetime.datetimeに与えてやる

certain_time = datetime.datetime(2020, 0, 0, tzinfo=JST)  # キーワード引数として与えるときは tzinfo

now = datetime.datetime.now(JST)

こうすると、イイ感じで日本の時間になってくれます。

更になんと、アメリカとか(世界協定時刻-7とか)にするとサマータイムの対応まで自動でやってくれます。wow

timestampから日本時刻に直すには

stamp = datetime.datetime.now(JST).timestamp()

stamp
# 1546266904.187328
datetime.datetime.fromtimestamp(stamp, tz=JST)
# datetime.datetime(2018, 12, 31, 23, 35, 4, 187328, tzinfo=datetime.timezone(datetime.timedelta(0, 32400), 'JST'))

といった感じで、tzとしてdatetime.timezoneインスタンスを与えてあげます。


注意点

タイムゾーンに関する情報を与えたdatetime.datetimeオブジェクトはaware、そうでないものはnaiveと呼ばれ、互いの比較、演算ができません。

datetime.datetime(2019, 1, 1) - datetime.datetime.now()

# datetime.timedelta(0, 1225, 880213)

datetime.datetime(2019, 1, 1) - datetime.datetime.now(JST)
# ---------------------------------------------------------------------------
# TypeError Traceback (most recent call last)
# <ipython-input-35-33a1ced3b530> in <module>()
# ----> 1 datetime.datetime(2019, 1, 1) - datetime.datetime.now(JST)

# TypeError: can't subtract offset-naive and offset-aware datetimes

datetime.datetime(2019, 1, 1) > datetime.datetime.now(JST)
# ---------------------------------------------------------------------------
# TypeError Traceback (most recent call last)
# <ipython-input-36-3121cc180bc8> in <module>()
# ----> 1 datetime.datetime(2019, 1, 1) > datetime.datetime.now(JST)

# TypeError: can't compare offset-naive and offset-aware datetimes

つまり、一つのプロジェクトの中で複数のdatetime.datetimeオブジェクトを扱うときは、どっちかにそろえたほうが良いってことだね。