発生事象
Djangoでdatetimeから取得した時間とDB(MySQL)から取得した時間がずれる。
また、Djangoの管理画面上で表示される時間がUTC時間になってしまう。
時間ずれの具体例
・DBから取得した時間のずれ
# DBから時間を取得(レコードは直近で登録したもの)
query_set_obj = ScrapingData.objects.all().filter(name=table_name)
update_time = query_set_obj[0].update_at
# datetimeから時間を取得
datetime_now = datetime.datetime.now()
# 時間を比較しても一致しない!
print(update_time.strftime("%H:%M")) # 00:00 と出力される。
print(datetime_now.strftime("%H:%M")) # 09:00 と出力される。
・Django管理画面の時間のずれ
時間がずれてしまう原因
setting.pyのTIME_ZONE が 'Asia/Tokyo' となっていれば datetimeで取得した時間やテンプレートで表示する時間はUTCからJST(日本時間)に変換されて表示される。(タイムゾーン有り時間aware)
しかし、TIME_ZONE が 'Asia/Tokyo' となっていても、USE_TZ が True となっていると、DBに対してレコードの作成や更新を行った際に保存される時間はUTCとなり、SELECT実行時もUTC時間で出力されるため時間のずれが生じる。
# setting.py
TIME_ZONE = 'Asia/Tokyo'
LANGUAGE_CODE = 'ja'
USE_I18N = True
USE_L10N = True
USE_TZ = True # ここが原因
時間のずれを調整する方法
解決方法のひとつとしては、USE_TZ を False にすればJSTで時間がDBに格納されるようになる。
しかしマルチロケール化を視野に入れている場合は非推奨の方法となる。(一般的にもUSE_TZはTrueにしておくのが習わしの模様)
一番簡単なのは、DBから取得した時間に対して、時差分の9時間を加算する方法です。
それにはdatetime.timedeltaオブジェクトを使用します。
# DBから時間を取得 (レコードは直近で登録したもの)
query_set_obj = ScrapingData.objects.all().filter(name=table_name)
update_time = query_set_obj[0].update_at
# DBから取得した時間に対して9時間加算する
update_time = update_time + datetime.timedelta(hours=9)
# datetimeから時間を取得
datetime_now = datetime.datetime.now()
# 時間が一致
print(update_time.strftime("%H:%M)) # 09:00 と出力される。
print(datetime_now.strftime("%H:%M")) # 09:00 と出力される。
Django管理画面上の時間表記も、models.pyを同様の方法で修正すると日本時間になります。
# models.py
class Data(models.Model):
name = models.CharField('データ名', max_length=50, default='')
created_at = models.DateTimeField('作成日', default=timezone.now)
update_at = models.DateTimeField('更新日', default=timezone.now)
def __str__(self):
# 管理画面で表示する時間に9時間加算する
datetime_now = self.update_at + datetime.timedelta(hours=9)
datetime_now = datetime_now.strftime("%Y/%m/%d %H:%M:%S")
return f'{self.name} {datetime_now}'
Djangoの参考書
参考
https://mizzsugar.hatenablog.com/entry/2019/11/07/094230
https://qiita.com/t_toriumi/items/50bad616d35f07e3340c