山pの楽しいお勉強生活

勉強の成果を垂れ流していきます

Pythonでjsonを読み込み、出力する際にdateやdatetime型を使用する

出力の時の話はよく記載がありましたが、読み込みの際に変換する方法はあまりなかったのでメモ。

概要

jsonでは日付型というのは定義されていません。(そもそもどう表現する?) そのため、pythonjsonを読み込みの際に日付が含まれていても文字列になりますし、出力の際にdate型が含まれているとエラーになります。

対応方法としては読み込むためのloadsではobject_hook、出力のためのdumpsはdefaultというオプションがあるので、こちらを設定することで対応が可能です。

対応前のコード

import json
data = '{"date" : "2019/02/08"}'
d = json.loads(data)
type(d['date']) # str
import json
from datetime import datetime
data = {'date' : datetime.now()}
json.dumps(data)
# TypeError: Object of type 'datetime' is not JSON serializable

対応後

詳しくは下記のコードを見てください。 出力時は型を調べて文字列に変換するだけなので何の問題もないですが、読み込み時は何らかの条件で日付を判別しdate型に変換しています。 (jsonには明示的に日付を示す構文はないためしょうがない。) ここではキーの末尾が「date」の場合に、date型に変換するようにしています。

import re
import json
from datetime import datetime, date

DATE_FORMAT = '%Y/%m/%d'
DATE_KEY = re.compile(r'date$')

def _json_parser(dct):
    for k, v in dct.items():
        if re.search(DATE_KEY, k):
            dct[k] = datetime.strptime(v, DATE_FORMAT).date()
    return dct

json_str = '{"hoge_date" : "2019/01/02", "l" : [{"huga_date" : "2018/12/31"}]}'
dct = json.loads(json_str, object_hook=_json_parser)
print(dct)
print(type(dct['hoge_date'])) # <class 'datetime.date'>
print(type(dct['l'][0]['huga_date'])) # <class 'datetime.date'>

def json_serial(obj):
    if isinstance(obj, date):
        return obj.strftime(DATE_FORMAT)
    return obj
json.dumps(dct, default=json_serial)

参考