datetime.datetime.now()
で取得したdatetimeオブジェクトを使ってDBに値を保存しようとしたら
以下のwarningがでた。
RuntimeWarning: DateTimeField ItemList.created received a naive datetime (2018-06-30 15:27:40.224351) while time zone support is active.
これきっかけでpython3のdatetimeについて調べた。
結果的には取得したdatetimeオブジェクトにtimezone情報がなかったことが原因であることはわかったが、
このあたりの全体像がわかるまでちょっと時間がかかった。
python3のdatetimeにはnativeとawareが存在する
nativeとはタイムゾーン情報を持たないdatetimeオブジェクトで、
awareとはタイムゾーン情報を持ったdatetimeオブジェクト。
例えばawareでtimezoneがutcで2018年1月1日12時10分10秒を表している場合、
日本時間は+9時間であるとわかる。
nativeで2018年1月1日12時10分10秒を表している場合、
そもそもこれがどこのtimezoneで表された時刻なのか不明なため、日本時間もわからない。
例えば日本のみで使われる前提であれば「日本時間を表す」という前提でnativeで扱ってもいいが、
内部的にutcのawareで扱い適宜現地のtimezoneに変換して表示する、というのがベストプラクティスらしい。
awareのdatetimeオブジェクトの作り方
このあたりがなかなか理解できなかったのだが、
python3の公式ドキュメントによるとawareの現在時刻を取得するには、datetime.datetime.now()の引数にdatetime.tzinfoを継承したタイムゾーン情報を定義したクラスを自分で定義し、このクラスのインスタンスを渡す必要があるらしい。
で、このクラスを自分で定義するのが結構めんどうなので、このあたりをまるっと提供してくれているライブラリとしてpytzがあるので、これをつかうのがデファクトスタンダードになっているらしい。
import pytz import datetime now = datetime.datetime.now(pytz.timezone('UTC')) # 上記nowを日本時間で扱いたければ now.astimezone(pytz.timezone('Asia/Tokyo')) # 特定の時間のdatetimeがほしければ my_time = datetime.datetime(2018,6,30,12,0,0,0,pytz.timezone('Asia/Tokyo'))
djangoであれば、
from django.utils import timezone utc_now = timezone.now() # utc local_now = timezone.localtime() # local
で、それぞれutcとlocalでの現在時刻が取得できる。
※local時間の取得方法についてchihiroyさんにお教えいただきました。ありがとうございます。