▶ 初学者向けにPythonを使ったデータ分析に役立つ記事を書いています
はじめに
今回は日時オブジェクトの引き算について基本から解説します。Pythonで日次オブジェクトの引き算をするときにうまくいかなかったことはありませんか?私はタイムゾーンの処理をした日時オブジェクトとタイムゾーンの概念を持たない日付型オブジェクトで演算をしているからかもしれません。基本から見ていきましょう。
環境
- Windows10
- Python 3.9.7
- pandas 1.5.0
- numpy: 1.23.3
- matplotlib: 3.6.1
日時のオブジェクト
日時のオブジェクトは、それらがタイムゾーンの情報を含んでいるかどうかによって “aware” あるいは “naive” に分類されます。
aware オブジェクトはタイムゾーンや夏時間の情報のような情報を持っています。awareオブジェクトは他の aware オブジェクトとの引き算ができます。
naive オブジェクトは協定世界時 (UTC) や現地時間、タイムゾーンなどの情報を持ちません。また、naiveオブジェクトは他のnaiveオブジェクトとの引き算ができます。
つまり、日時のオブジェクトはaware, naiveの種類が揃っていないと引き算の演算ができません。
オブジェクトが Aware なのか Naive なのかの判断¶
日付のオブジェクトがaware、あるいは、naiveで揃っていないと引き算ができません。そのため対象のオブジェクトがaware、なのか、naiveなのかを判別する必要があります。
ここでは、その判別方法を見ていきましょう。
詳細はPythonの公式ドキュメントを参考にしてください。
となります。次にtime型、datetime型がawareであるか、naiveであるかの判別方法を見ていきましょう。
time型オブジェクトのaware/naiveの判定
次の条件を両方とも満たす場合、 time
オブジェクトtは aware です:
t.tzinfo
がNone
でないt.tzinfo.utcoffset(None)
がNone
を返さない
どちらかを満たさない場合は、その time
オブジェクトは naive です。
※簡易的にtzinfoをもっていればaware、持っていなければnaiveと考えていれば、多くの場合問題ありません。
datetime型オブジェクトのaware/naiveの判定
次の条件を両方とも満たす場合、 datetime
オブジェクトd は aware です:
d.tzinfo
がNone
でないd.tzinfo.utcoffset(d)
がNone
を返さない
どちらかを満たさない場合は、 datetime
オブジェクト は naive です。
※簡易的にtzinfoをもっていればaware、持っていなければnaiveと考えていれば、多くの場合問題ありません。
日時オブジェクトの引き算
既に説明したように、日時のオブジェクトはaware, naiveの種類が揃っていないと引き算の演算ができません。そのため、日時のオブジェクトの比企さんの演算は、次のいずれかになります。
- awareオブジェクト同士での引き算
- naiveオブジェクト同士での引き算
日次のオブジェクトがawareであるか、naiveであるかの判定方法は既に解説したので、aware⇔naiveの変換ができれば、aware同士の演算、naive同士の演算をすることができます。
aware同士で引き算をする
簡単な例でみていきましょう。まず、日時のオブジェクトを2つ作ります。
import datetime
dt1 = datetime.datetime(2023,5,5,10,00,00) #naive
dt2 = datetime.datetime(2023,5,5,19,00,00,
tzinfo=datetime.timezone(datetime.timedelta(hours=9))) #aware
print(dt1)
print(type(dt1))
print(dt1.tzinfo)
print('-'*10)
print(dt2)
print(type(dt2))
print(dt2.tzinfo)
dt1はtzinfoを持たないのでnaive, dt2はawareです。dt1とdt2をそのまま引き算すると、エラーとなります。やってみましょう。
ここでは、dt2をnaiveにして計算してみましょう。
# dt2のtzinfoにNoneを与えてnaiveにして計算
dt2 = dt2.replace(tzinfo=None)
dt2 - dt1
今度はうまくいきました。dt2のtzinfoをNoneとしたので、2023年5月5日19時00分として扱われます。dt1が2023年5月5日10時00分なのでその差は9時間です。計算結果が32400秒なのでちょうど、9時間ですね。
naive同士で引き算をする
もう一度、dt1とdt2を作り直します。
import datetime
dt1 = datetime.datetime(2023,5,5,10,00,00) #naive
dt2 = datetime.datetime(2023,5,5,19,00,00,
tzinfo=datetime.timezone(datetime.timedelta(hours=9))) #aware
print(dt1)
print(type(dt1))
print(dt1.tzinfo)
print('-'*10)
print(dt2)
print(type(dt2))
print(dt2.tzinfo)
d1はnaive, dt2がawareになっています。今度はdt1をawareにして計算してみましょう。先ほどと同様にreplaceを使います。コントはtzinfoにタイムゾーンの情報を指定します。ここではUTCにしましょう。
# dt1のタイムゾーンにUTCを指定する
dt1 = dt1.replace(tzinfo=datetime.timezone.utc)
これでdt1,dt2ともにawareとなりました。
dt1:UTCで2023年5月5日10時00分
dt2:JSTで2023年5月5日19時00分
※dt2はUTC+9hourとしているのでJSTとしています
この差分を計算してみましょう。
dt2 - dt1
JSTの2023年5月5日19時00分は、UTCの2023年5月5日10時00分なので、差がない、という結果となるのですね。
まとめ
今回は日時オブジェクトの差分について基本から解説しました。日時オブジェクトにはnaiveとawareがあり、これらが揃っていないと差分を計算することができません。naiveとawareは、tzinfoを持っているかどうかで判別できます。
awareとnaiveの変換は次のようにします。
- aware→naiveはreplaceを使って、tzinfoにNoneを指定
- naive→awareはreplaceを使って、tzinfoにタイムゾーンを指定
コメント