こんにちは!Masaです。
今回はPythonでの時間の概念”naive”と”aware”について解説していきます
先日、Python、Djangoにて日付を扱う操作をしていたら以下のエラーが出ました。
typeerror: can’t subtract offset-naive and offset-aware datetimes
直訳だと「オフセット非対応とオフセット対応のデータの引き算ができない」という意味になります。
この問題について解説していきます!
naiveとawareとは
まずこの問題は、Pythonのdatetimeモジュールを使用した際に発生しました。
datetimeモジュールは
- 日付表現のdateオブジェクト
- 時間表現のtimeオブジェクト
- 日付と時間表現のdatetimeオブジェクト
の3種類があります。
そしてdatetimeモジュールには2つの種類があります。(Pythonドキュメントより)
- aware:タイムゾーンや夏時間など、時間調節に関する知識を持っている実時刻を表現
- naive:タイムゾーンなどの時間調整に関する知識持たず、時間表現だけを行う。
つまり、awareはタイムゾーンや夏時間など、上手に利用すれば便利だが扱いにくいです。
一方、naiveはawareにある時間調節に関する知識を外しているため、簡単に理解でき、上手に利用することができます。
- date型のオブジェクトは常にnaive
- time型あるいはdatetime型のオブジェクトはawareかnaiveのどちらか
であり、awareとnaiveの判別には、タイムゾーン情報の属性tzinfoを持つかどうかで見極めます。
can’t subtract offset-naive and offset-aware datetimesの原因
そしてエラーの原因は、naiveのdatetimeオブジェクトとawarのdatetimeオブジェクトで引き算をしてしまったために発生しました
以下のサンプルプログラムから見ていきましょう。
import datetime
dt1 = datetime.datetime.now() #naive
dt2 = datetime.datetime.now(datetime.timezone.utc) #aware
上記のコードはどちらも現在時刻を取得しています。
dt1がnaiveなオブジェクト、dt2がawareなオブジェクトとなります。
awareなオブジェクトを取得したい場合は、タイムゾーン情報を指定する必要があります。
この状態で以下の命令をすると、エラーの原因になります。
delta = dt1 - dt2
この場合の解決方法の1つとして、どちらかの形に合わせてあげましょう。
解決法
両方ともnaiveに合わせる場合
import datetime
dt1 = datetime.datetime.now() #naive
dt2 = datetime.datetime.now(datetime.timezone.utc) #aware
dt2 = dt2.replace(tzinfo=None)
delta = dt1 - dt2
awareに合わせる場合
import datetime
import pytz
dt1 = datetime.datetime.now() #naive
dt2 = datetime.datetime.now(datetime.timezone.utc) #aware
dt1 = pytz.utc.localize(dt1)
delta = dt1 - dt2
この場合、タイムゾーンを表すライブラリーである、pytzを使用しています。
pipでpytzをインストールしてから使用して下さい。
Djangoバージョン
自分自身はDjangoにてこのエラーが発生したため、Djangoでの解決方法も載せておきます。
両方ともnaiveに合わせる場合
import datetime
from django.utils.timezone import make_naive
dt1 = datetime.datetime.now() #naive
dt2 = datetime.datetime.now(datetime.timezone.utc) #aware
dt2 = make_naive(dt2)
delta = dt1 - dt2
両方ともnaiveに合わせる場合
import datetime
from django.utils.timezone import make_aware
dt1 = datetime.datetime.now() #naive
dt2 = datetime.datetime.now(datetime.timezone.utc) #aware
dt1 = make_aware(dt1)
delta = dt1 - dt2
まとめ
本日はdatetimeモジュールのawareとnaiveについてでしたが、いかがだったでしょうか。
日付は協定時間や夏時間などがあり、細かく見ていかないと不都合が生じる可能性があるので、気を付けましょう!
最後まで読んでいただきありがとうございます。
自己学習に役立てていただけたら嬉しく思います
また、SNSやブログでシェアしていただくことや、誤植などをコメントで指摘いただけたら幸いです。
コメント