PythonでISO 8601形式の文字列と日時datetimeを相互変換
Pythonで日時(日付・時刻)の情報を扱うには標準ライブラリのdatetimeモジュールを使う。ISOフォーマット(ISO 8601)の文字列とdatetimeオブジェクトなどを相互に変換するisoformat()やfromisoformat()が用意されている。
datetime, date, timeオブジェクトの基本や、ISO形式ではない任意の形式の文字列との相互変換については以下の記事を参照。
日時(日付・時刻)を文字列に変換: isoformat()
日時(日付・時刻)をISOフォーマット(ISO 8601)の文字列に変換するには、date, time, datetimeオブジェクトのisoformat()メソッドを使う。
dateオブジェクトを変換
以下のdateオブジェクトを例とする。
import datetime
d = datetime.date(2023, 4, 1)
print(d)
# 2023-04-01
print(type(d))
# <class 'datetime.date'>
isoformat()でISOフォーマット(ISO 8601)の文字列に変換できる。
print(d.isoformat())
# 2023-04-01
print(type(d.isoformat()))
# <class 'str'>
timeオブジェクトを変換
以下のtimeオブジェクトを例とする。
t = datetime.time(5, 0, 30, 1000)
print(t)
# 05:00:30.001000
print(type(t))
# <class 'datetime.time'>
isoformat()でISOフォーマット(ISO 8601)の文字列に変換できる。
print(t.isoformat())
# 05:00:30.001000
print(type(t.isoformat()))
# <class 'str'>
第一引数timespecで結果に含める要素を指定できる。デフォルトはtimespec='auto'で、マイクロ秒が0のときは'seconds'、そうでない場合は'microsecond'となる。
print(t.isoformat('hours'))
# 05
print(t.isoformat('minutes'))
# 05:00
print(t.isoformat('seconds'))
# 05:00:30
print(t.isoformat('milliseconds'))
# 05:00:30.001
print(t.isoformat('microseconds'))
# 05:00:30.001000
datetimeオブジェクトを変換
以下のdatetimeオブジェクトを例とする。
dt = datetime.datetime(2023, 4, 1, 5, 0, 30, 1000)
print(dt)
# 2023-04-01 05:00:30.001000
print(type(dt))
# <class 'datetime.datetime'>
isoformat()でISOフォーマット(ISO 8601)の文字列に変換できる。
print(dt.isoformat())
# 2023-04-01T05:00:30.001000
print(type(dt.isoformat()))
# <class 'str'>
デフォルトでは日付と時刻の間の文字はT。第一引数sepで任意の一文字を指定できる。二文字以上の文字列を指定するとエラー。
print(dt.isoformat(' '))
# 2023-04-01 05:00:30.001000
print(dt.isoformat('x'))
# 2023-04-01x05:00:30.001000
# print(dt.isoformat('xx'))
# TypeError: isoformat() argument 1 must be a unicode character, not str
timeの場合と同様に、第二引数timespecで結果に含める時刻の要素を指定できる。デフォルトはtimespec='auto'で、マイクロ秒が0のときは'seconds'、そうでない場合は'microsecond'となる。
print(dt.isoformat(timespec='hours'))
# 2023-04-01T05
print(dt.isoformat(timespec='minutes'))
# 2023-04-01T05:00
print(dt.isoformat(timespec='seconds'))
# 2023-04-01T05:00:30
print(dt.isoformat(timespec='milliseconds'))
# 2023-04-01T05:00:30.001
print(dt.isoformat(timespec='microseconds'))
# 2023-04-01T05:00:30.001000
日付のみや時刻のみの文字列に変換したい場合はdate(), time()でdate, timeオブジェクトに変換してからisoformat()で文字列に変換すればよい。
print(dt.date().isoformat())
# 2023-04-01
print(dt.time().isoformat())
# 05:00:30.001000
文字列を日時(日付・時刻)に変換: fromisoformat()
ISOフォーマット(ISO 8601)の文字列を日時(日付・時刻)に変換するには、date, time, datetimeクラスのクラスメソッドであるfromisoformat()を使う。
fromisoformat()はPython3.7で追加された。また、後述のように、Python3.11からISO 8601の基本形式にも対応するようになった。
dateオブジェクトに変換
fromisoformat()でISO 8601形式の文字列をdateオブジェクトに変換できる。
d = datetime.date.fromisoformat('2023-04-01')
print(d)
# 2023-04-01
print(type(d))
# <class 'datetime.date'>
年月日が省略されていたり、桁数が合っていなかったりするとエラー。年は4桁、月日は2桁で0埋めが必要。
# print(datetime.date.fromisoformat('2023-04'))
# ValueError: Invalid isoformat string: '2023-04'
# print(datetime.date.fromisoformat('2023-4-1'))
# ValueError: Invalid isoformat string: '2023-4-1'
timeオブジェクトに変換
fromisoformat()でISO 8601形式の文字列をtimeオブジェクトに変換できる。
t = datetime.time.fromisoformat('05:00:30.001000')
print(t)
# 05:00:30.001000
print(type(t))
# <class 'datetime.time'>
分や秒、マイクロ秒が省略されていると0とみなされる。
print(datetime.time.fromisoformat('05'))
# 05:00:00
時間、分、秒は0埋めされた2桁表記でないとエラー。
# print(datetime.time.fromisoformat('5:00:30'))
# ValueError: Invalid isoformat string: '5:00:30'
datetimeオブジェクトに変換
fromisoformat()でISO 8601形式の文字列をdatetimeオブジェクトに変換できる。
dt = datetime.datetime.fromisoformat('2023-04-01T05:00:30.001000')
print(dt)
# 2023-04-01 05:00:30.001000
print(type(dt))
# <class 'datetime.datetime'>
日付と時刻の間の文字はT以外でも一文字であればOK。二文字以上はエラー。
print(datetime.datetime.fromisoformat('2023-04-01x05:00:30.001000'))
# 2023-04-01 05:00:30.001000
# print(datetime.datetime.fromisoformat('2023-04-01xx05:00:30.001000'))
# ValueError: Invalid isoformat string: '2023-04-01xx05:00:30.001000'
分や秒の値を省略すると0とみなされる。
print(datetime.datetime.fromisoformat('2023-04-01T05'))
# 2023-04-01 05:00:00
print(datetime.datetime.fromisoformat('2023-04-01'))
# 2023-04-01 00:00:00
date, timeオブジェクトと同様に、桁数が合っていないとエラー。0埋めが必要。
# print(datetime.datetime.fromisoformat('2023-4-1T5:00'))
# ValueError: Invalid isoformat string: '2023-4-1T5:00'
日付と時刻を含む文字列をdate, timeオブジェクトに変換したい場合は、datetimeオブジェクトに変換してからdate(), time()でdate, timeオブジェクトに変換する。
s = '2023-04-01T05:00:30.001000'
# print(datetime.date.fromisoformat(s))
# ValueError: Invalid isoformat string: '2023-04-01T05:00:30.001000'
d = datetime.datetime.fromisoformat(s).date()
print(d)
# 2023-04-01
print(type(d))
# <class 'datetime.date'>
ISO 8601の基本形式と拡張形式
ISO 8601には、ハイフン-やコロン:を区切り文字として含む拡張形式(拡張表記)と、含まない基本形式(基本表記・標準表記)がある。
- 拡張形式:
2023-04-01T05:00:30.001000 - 基本形式:
20230401T050030.001000
Python 3.11からfromisoformat()が基本形式に対応
Python 3.11からfromisoformat()が基本形式に対応するようになった。
print(datetime.date.fromisoformat('20230401'))
# 2023-04-01
print(datetime.time.fromisoformat('050030.001000'))
# 05:00:30.001000
print(datetime.datetime.fromisoformat('20230401T050030.001000'))
# 2023-04-01 05:00:30.001000
それ以前のバージョンではstrptime()に適切なフォーマット文字列を指定する必要がある。
print(datetime.datetime.strptime('20230401T050030.001000', '%Y%m%dT%H%M%S.%f'))
# 2023-04-01 05:00:30.001000
基本形式と拡張形式の文字列の変換
これまでの例のように、isoformat()は日時を拡張形式の文字列に変換する。拡張形式の文字列を区切り文字を含まない基本形式に変換したい場合は文字列メソッドを使う。
例えばreplace()でハイフン-とコロン:を削除する方法が考えられる。
s = '2023-04-01T05:00:30.001000'
print(s.replace('-', '').replace(':', ''))
# 20230401T050030.001000
ミリ秒以下を無視したい場合はsplit()で小数点(ピリオド).で分割した最初の要素を対象とすればよい。
print(s.split('.')[0].replace('-', '').replace(':', ''))
# 20230401T050030
基本形式を拡張形式に変換したい場合はdatetimeオブジェクトに変換してからisoformat()で再度文字列に戻す。上述のように、基本形式の文字列からdatetimeオブジェクトへの変換には、Python 3.11以降はfromisoformat()、それより前のバージョンではstrptime()を使う。
s_basic = '20230401T050030.001000'
print(datetime.datetime.fromisoformat(s_basic).isoformat())
# 2023-04-01T05:00:30.001000
タイムゾーン情報を含む場合
これまでの例のようにタイムゾーンの情報を含まない文字列をfromisoformat()で変換した場合、tzinfo属性はNoneとなる。
s = '2023-04-01T05:00:30.001000'
dt = datetime.datetime.fromisoformat(s)
print(dt)
# 2023-04-01 05:00:30.001000
print(dt.tzinfo)
# None
末尾に+09:00のようなタイムゾーン情報を含む場合、tzinfo属性に値が格納される。
s = '2023-04-01T05:00:30.001000+09:00'
dt = datetime.datetime.fromisoformat(s)
print(dt)
# 2023-04-01 05:00:30.001000+09:00
print(dt.tzinfo)
# UTC+09:00
tzinfo属性に値が格納されていれば、isoformat()で文字列に変換する場合、その値に基づいて末尾にタイムゾーンを表す文字列が追加される。
print(dt.isoformat())
# 2023-04-01T05:00:30.001000+09:00
UTC(協定世界時)を表す末尾のZ
UTC(協定世界時)を表す場合は末尾にZを付ける。
Python 3.11以降
Python 3.11からfromisoformat()は末尾のZを正しく処理するようになった。
s = '2023-04-01T05:00:30.001000Z'
dt = datetime.datetime.fromisoformat(s)
print(dt)
# 2023-04-01 05:00:30.001000+00:00
print(dt.tzinfo)
# UTC
Python 3.11より前
Python 3.11より前のバージョンのfromisoformat()では末尾にZが付いた文字列はエラーになる。
末尾のZを処理するには+00:00に置き換える方法がある。この場合、tzinfo属性に情報が付与される。
s = '2023-04-01T05:00:30.001000Z'
dt_utc = datetime.datetime.fromisoformat(s.replace('Z', '+00:00'))
print(dt_utc)
# 2023-04-01 05:00:30.001000+00:00
print(dt_utc.tzinfo)
# UTC
末尾のZを削除した場合はtzinfo属性がNoneとなる。タイムゾーンを考慮する必要がなければこちらでもよい。
dt_none = datetime.datetime.fromisoformat(s.replace('Z', ''))
print(dt_none)
# 2023-04-01 05:00:30.001000
print(dt_none.tzinfo)
# None
datetimeやpytzを使ったタイムゾーンの処理についての詳細は以下の記事を参照。