PythonでISO8601(RFC3339)を扱う

More than 1 year has passed since last update.


はじめに

APIでスタンダードな日付形式であるISO8601について、Pythonで扱うのに軽くはまったのでメモ。

ISO8601形式は様々な書き方ができますが、有名どころのAPIでは以下の2種類が多いと思います。



  • UTC


    • 2016-12-31T20:02:05.123456Z




  • APIのパラメータやサービスで設定したタイムゾーン


    • 2016-12-31T20:02:05.123456+0900




文字列 -> datetime

APIからJsonで戻ってきた文字列をPythonのdatetimeに変換します。常にJSTで統一しています。

datetimeはそのまま、>, < での比較ができ、timedeltaによる日付の計算ができるため、プログラム内では常にdatetimeで表現するのがよいかと思います。

def iso_to_jstdt(iso_str):

dt = None
try:
dt = datetime.strptime(iso_str, '%Y-%m-%dT%H:%M:%S.%fZ')
dt = pytz.utc.localize(dt).astimezone(pytz.timezone("Asia/Tokyo"))
except ValueError:
try:
dt = datetime.strptime(iso_str, '%Y-%m-%dT%H:%M:%S.%f%z')
dt = dt.astimezone(pytz.timezone("Asia/Tokyo"))
except ValueError:
pass
return dt


datetime -> 表示用文字列

datetimeを画面なりに出力する文字列に変換します。

ここでは"/"区切りの日本風です。上記の関数でdatetimeにしてあれば日本時間で表示されます。

def dt_to_str(dt):

if dt is None:
return ''
return dt.strftime('%Y/%m/%d %H:%M:%S')


datetime -> ISO文字列

次のプログラムとのI/Fなど、親システム的にするにはISO形式で出力しておくとよいでしょう。

def dt_to_isostr(dt):

if dt is None:
return ''
return dt.isoformat()


example

上記変換処理の実行例です。

ここでは不正なフォーマットはNone,空文字で表現していますが、場合によっては最小の日付、最大の日付などで表現するという方法もありますね。

●サンプルプログラム

print('test1----------------------------')

dt1 = iso_to_jstdt('2016-12-31T20:02:05.123456Z')
print(dt1)
print(dt_to_str(dt1))
print(dt_to_isostr(dt1))

print('test2----------------------------')
dt2 = iso_to_jstdt('2016-12-31T20:02:05.123456+0900')
print(dt2)
print(dt_to_str(dt2))
print(dt_to_isostr(dt2))

print('test3----------------------------')
dt3 = iso_to_jstdt('2016-12-31T20:02:05.123456-0300')
print(dt3)
print(dt_to_str(dt3))
print(dt_to_isostr(dt3))

print('test4----------------------------')
dt4 = iso_to_jstdt('2016/12/31T20:02:05.123456Z')
print(dt4)
print(dt_to_str(dt4))
print(dt_to_isostr(dt4))

print('--------------------------------')

●実行結果

test1----------------------------

2017-01-01 05:02:05.123456+09:00
2017/01/01 05:02:05
2017-01-01T05:02:05.123456+09:00
test2----------------------------
2016-12-31 20:02:05.123456+09:00
2016/12/31 20:02:05
2016-12-31T20:02:05.123456+09:00
test3----------------------------
2017-01-01 08:02:05.123456+09:00
2017/01/01 08:02:05
2017-01-01T08:02:05.123456+09:00
test4----------------------------
None

--------------------------------


おわりに

Pythonに限らずですが、日付・時刻の扱いは面倒です。

終わりだよ~


参考

8.1. datetime — 基本的な日付型および時間型 — Python 3.6.3 ドキュメント