結論
datetime.datetime
型同士の演算をするときに、日時表現が異なるもので演算を行ったために発生するエラーです。make_naive
やmake_aware
関数を使用して表現をそろえることで解決できます。
エラーを再現
以下のコードを実行するとエラーが発生します。
import datetime
dt1 = datetime.datetime.now()
dt2 = datetime.datetime.now(datetime.timezone.utc)
dt2 - dt1
TypeError: can't subtract offset-naive and offset-aware datetimes
原因
以下の記事が参考になります。
どうやら、datetime.datetime
型の変数はaware
とnaive
という日時表現があるようです。この表現が異なるもの同士を演算することができないことから起きるエラーのようでした。
aware: タイムゾーン、サマータイムも含めた日時表現
naive: タイムゾーン、サマータイムは含めない日時表現
実際にエラーが発生したコードの変数をprintしてみるとわかりやすいです。
import datetime
dt1 = datetime.datetime.now()
dt2 = datetime.datetime.now(datetime.timezone.utc)
print(dt1) # naive表現
print(dt2) # aware表現
2023-06-21 05:47:29.994050
2023-06-21 05:47:29.994103+00:00
これがdjangoで起きる原因
私も全てを理解できているわけではないうえで書くことになる点、ご了承ください。djangoではモデルの日時型フィールドはaware表現のものを扱っているように思います。それゆえ、例えばdatetime.datetime.now()
などで取得した変数と演算すると、異なる表現同士を演算しようとしてエラーが発生することになります。
解決策
表現をそろえることで解決できます。
djangoには表現をそろえる関数であるmake_naive
やmake_aware
があるので、それを使用していきます。
import datetime
from django.utils.timezone import make_naive
dt1 = datetime.datetime.now()
dt2 = datetime.datetime.now(datetime.timezone.utc)
# ともにnaive表現になる
dt1 - make_naive(dt2)
上記のコードだとdt2がnaive表現になるので、両方ともnaive表現で演算できるということになります。
補足
そもそも、datitime.datetime
型同士を演算するとどのような結果が返ってくるのか。これについては以前の私の記事が参考になります。
以上です。
参考