タイムゾーンを意識してdatetimeを扱う際色々混乱してしまったので、自分用にまとめておきます。
Naive,Aware
Pythonの日時オブジェクトは以下の2種類に分類される。ざっくりとした差はタイムゾーン情報の有無
。
-
Naiveオブジェクト
- タイムゾーン情報を持たない
-
Awareオブジェクト
- タイムゾーン情報(tzinfo属性)を持つ
- tzinfo属性にはtzinfoのサブクラスのインスタンスを設定出来る
- dateitme.timezoneがtzinfoのサブクラスなので、このクラスのオブジェクトを設定することが出来る
- 例えば、
datetime.timezone(timedelta(hours=+9), 'JST')
としてオブジェクトを生成するとこれはJSTのタイムゾーンを表すオブジェクト
したがって、何らかのプログラムでタイムゾーンを意識した処理を行いたい場合、Awareオブジェクトを使う必要がある。
オブジェクト
以下4つのメインオブジェクトがある。
- date: 年月日
- time: 時分秒
- datetime: 日付と時刻
- timedelta: 時間間隔
それぞれオブジェクトの生成の仕方によって、NaiveだったりAwareだったりする。
例えば、
>>> print('Python %s on %s' % (sys.version, sys.platform))
Python 3.7.4 (default, Oct 10 2019, 12:40:25)
[Clang 10.0.1 (clang-1001.0.46.4)] on darwin
>>> import datetime
>>> aware_dt = datetime.datetime.now(tz=datetime.timezone.utc)
>>> aware_dt
datetime.datetime(2020, 4, 4, 5, 49, 51, 291393, tzinfo=datetime.timezone.utc)
>>> naive_dt = datetime.datetime.utcnow()
>>> naive_dt
datetime.datetime(2020, 4, 4, 5, 50, 8, 499521)
>>> aware_dt.tzinfo
datetime.timezone.utc
>>> print(naive_dt.tzinfo)
<class 'NoneType'>
のように、utc現在時刻をオブジェクトとして生成するときも、タイムゾーンを指定する方法とそうでない方法がある。
datetimeオブジェクトにまつわるメソッド
strptime
日付を表現した文字列をdatetime型にするメソッド。
>>> str_dt = '2020-3-01 10:11:12'
>>> strp_dt = datetime.datetime.strptime(str_dt, "%Y-%m-%d %H:%M:%S")
>>> strp_dt
datetime.datetime(2020, 3, 1, 10, 11, 12)
>>> print(type(strp_dt.tzinfo))
<class 'NoneType'>
生成したオブジェクトにタイムゾーン属性は含まれない。
ただし、変換前の文字列にタイムゾーンが含まれていて、フォーマットも適切に設定すると
>>> str_dt_utc = '2020-3-01 10:11:12+00:00'
>>> strp_dt_utc = datetime.datetime.strptime(str_dt_utc, "%Y-%m-%d %H:%M:%S%z")
>>> strp_dt_utc
datetime.datetime(2020, 3, 1, 10, 11, 12, tzinfo=datetime.timezone.utc)
>>> str_dt_jst = '2020-3-01 10:11:12+09:00'
>>> strp_dt_jst = datetime.datetime.strptime(str_dt_jst, "%Y-%m-%d %H:%M:%S%z")
>>> strp_dt_jst
datetime.datetime(2020, 3, 1, 10, 11, 12, tzinfo=datetime.timezone(datetime.timedelta(seconds=32400)))
のようにタイムゾーン属性も設定されてdatetimeオブジェクトが生成される模様。
astimezone
あるdatetimeオブジェクトを指定したタイムゾーン情報に合わせて変換するメソッド。
>>> strp_dt.astimezone(datetime.timezone.utc)
datetime.datetime(2020, 3, 1, 1, 11, 12, tzinfo=datetime.timezone.utc)
JSTとUTCの時差である-9時間が反映され、tzinfoが付加されたdatetimeのオブジェクトが返却された。(これはローカルのタイムゾーンとの比較によるもの?)
replace
あるdatetimeオブジェクトのタイムゾーンを指定したタイムゾーンに変換するメソッド。
>>> strp_dt.replace(tzinfo=datetime.timezone.utc)
datetime.datetime(2020, 3, 1, 10, 11, 12, tzinfo=datetime.timezone.utc)
astimezoneと比較すると、tzinfoだけが変換されていることに注意。
timezoneオブジェクトの生成については、素直にdatetime.timezone(timedelta(hours=+9), 'JST')
のように生成する方法や、サードパーティ製のモジュール(pytz,dateutil)を使ったりと、色々な方式がある。