【Python基礎】datetimeモジュールでのタイムゾーンの設定

  • URLをコピーしました!
目次

datetime

前回、PandasのデータフレームをHTML化する方法を紹介しました。

今回はdatetimeモジュールで日時を取得した際にたまに重要となるタイムゾーンのお話です。

私がタイムゾーンを気にし出したのは、Twitterのbotを作っている時でした。

色々なツイートをデータベースに保存するのですが、気にせずに「datetime.datetime.now()」で日時を取得し、そのままデータベースに放り込んでいました。

しかしある時、Twitter APIから得られた日時と比較しようとしたときにエラーとなってしまい、なぜかなと思って調べた結果、タイムゾーンが原因だったわけです。

その時の経験を記事にしてみようというのが今回のお話。

awareオブジェクトとnaiveオブジェクト

先ほどお話しした「datetime.datetime.now()」で得られた日時とTwitter APIから得られた日時でエラーとなったのは、「datetime.datetime.now()」で得られた日時にはタイムゾーンの情報がなく、Twitter APIから得られた日時ではタイムゾーンの情報があるという違いからでした。

タイムゾーンの情報がある日時のデータ(datetime型)をawareなオブジェクト、タイムゾーンの情報がない日時のデータをnaiveなオブジェクトといいます。

このawareオブジェクトとnaiveオブジェクトは直接計算ができず、そのためにエラーとなったわけです。

まず通常の「datetime.datetime.now()」で得られた日時と世界の時間の基準である世界協定時(Coordinated Universal Time、UTC)を作成してみます。

import datetime

timenow = datetime.datetime.now()
timenow_utc = datetime.datetime.now(datetime.timezone.utc)

print(timenow)
print(timenow.tzinfo)

print(timenow_utc)
print(timenow_utc.tzinfo)

2022-08-27 21:07:54.257376
None
2022-08-27 12:07:54.257502+00:00
UTC

UTCを取得するには「datetime.datetime.now()」のオプションに「datetime.timezone.utc」を追加します。

また得られたdatetime型のデータに対し、「.tzinfo」でタイムゾーンの情報が取得できます。

上の例では「2022-08-27 12:07:54.257502」が日時で「+00:00」が世界協定時からの時差です。

また「datetime.datetime.now()」で取得した日時では「.tzinfo」で取得したタイムゾーンの情報が「None」になっているのに対し、「datetime.datetime.now(datetime.timezone.utc)」では「UTC」になっています。

つまり「datetime.datetime.now()」にはタイムゾーンの情報がなく、「datetime.datetime.now(datetime.timezone.utc)」では「UTC」のタイムゾーンが使われていることになります。

そして前者がnaiveなオブジェクト、後者がawareなオブジェクトというわけです。

また日時に着目してみると「datetime.datetime.now()」で取得された日時は実行したPCの日時です。

それに対し「datetime.datetime.now(datetime.timezone.utc)」はUTCの時間なので、9時間引かれた日時になっています。

それではこれらを引き算してみましょう。

import datetime

timenow = datetime.datetime.now()
timenow_utc = datetime.datetime.now(datetime.timezone.utc)

print(timenow - timenow_utc)

実行結果
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [2], in <cell line: 6>()
      3 timenow = datetime.datetime.now()
      4 timenow_utc = datetime.datetime.now(datetime.timezone.utc)
----> 6 print(timenow - timenow_utc)

TypeError: can't subtract offset-naive and offset-aware datetimes

「can’t subtract offset-naive and offset-aware datetimes」とは「naiveなオブジェクトとawareなオブジェクトは引き算できませんよ」というエラーです。

ということで計算をしたい場合、どちらかの形式に揃える必要があります。

タイムゾーンの情報を変更:astimezoneとreplace

タイムゾーンの情報は「.astimezone(タイムゾーン)」、もしくは「.replace(tzinfo=タイムゾーン)」で変更します。

まずは「.astimezone(タイムゾーン)」を使って、「datetime.datetime.now()」で取得した日時のタイムゾーンをUTCに変更してみましょう。

import datetime

timenow = datetime.datetime.now()
timenow_utc = timenow.astimezone(datetime.timezone.utc)

print(timenow)
print(timenow.tzinfo)

print(timenow_utc)
print(timenow_utc.tzinfo)

実行結果
2022-08-27 21:14:46.076962
None
2022-08-27 12:14:46.076962+00:00
UTC

次に「.replace(tzinfo=タイムゾーン)」を使って、「datetime.datetime.now()」で取得した日時のタイムゾーンをUTCに変更してみましょう。

import datetime

timenow = datetime.datetime.now()
timenow_utc = timenow.replace(tzinfo=datetime.timezone.utc)

print(timenow)
print(timenow.tzinfo)

print(timenow_utc)
print(timenow_utc.tzinfo)

実行結果
2022-08-27 21:16:53.761349
None
2022-08-27 21:16:53.761349+00:00
UTC

ここでちょっと日時に注意してみてください。

実は「astimezone」で日時を変更した場合、時差分が自動で修正されます。

そのため「2022-08-27 21:14:46.076962」だった日時が、UTCのタイムゾーン情報変更後は「2022-08-27 12:14:46.076962+00:00」となっています。

逆に「replace」で日時を変更した場合、時差は修正されず、タイムゾーンの情報だけが変更されます。

そのため日時はUTCのタイムゾーン変更前は「2022-08-27 21:16:53.761349」で、変更後は「2022-08-27 21:16:53.761349+00:00」であり、日時は変わっていません。

タイムゾーンの作成:datetime.timezone

実際はUTCのタイムゾーンを使うよりも我々日本人としては日本のタイムゾーンが必要なことが多いでしょう。

それを簡単に扱うライブラリもあるようですが、今回は自分でタイムゾーンを作って使ってみます。

自分でタイムゾーンを作成するには「datetime.timezone(UTCからの時差, ‘名前’)」で作成できます。

ただしUTCからの時差もdatetime型で作成する必要があり、「datetime.timedelta(hours=時差)」を使います。

つまり「datetime.timezone(datetime.timedelta(hours=時差), ‘名前’)」と覚えておくのがいいかもしれません。

import datetime

JST_TZ = datetime.timezone(datetime.timedelta(hours=+9), 'JST')

timenow_utc = datetime.datetime.now(datetime.timezone.utc)
timenow_jst_astimezone = timenow_utc.astimezone(JST_TZ)
timenow_jst_replace = timenow_utc.replace(tzinfo=JST_TZ)

print(timenow_utc)
print(timenow_utc.tzinfo)

print(timenow_jst_astimezone)
print(timenow_jst_astimezone.tzinfo)

print(timenow_jst_replace)
print(timenow_jst_replace.tzinfo)

実行結果
2022-08-27 12:41:45.141586+00:00
UTC
2022-08-27 21:41:45.141586+09:00
JST
2022-08-27 12:41:45.141586+09:00
JST

これで日時を使いたい場所の時差さえ分かれば、タイムゾーンを設定できるようになりました。

次回はdatetime型のNan(欠損値)であるNaTをいじってみたので、その解説をしていきます。

ではでは今回はこんな感じで。

よかったらシェアしてね!
  • URLをコピーしました!

コメント

コメントする

目次