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