JSONシリアライズで、datetime を考慮するケースは、
JSONシリアライズで、datetime に注意する - Oboe吹きプログラマの黙示録
を書いたが、デシリアライズする場合も datetime オブジェクトに変換する場合は以下のような
メソッドをフックとして実行させる必要がある。
import json from datetime import datetime def datetime_parser(value): if isinstance(value, dict): for k,v in value.items(): value[k] = datetime_parser(v) elif isinstance(value, list): for i,e in enumerate(value): value[i] = datetime_parser(e) elif isinstance(value, str): try: value = datetime.strptime(value, '%Y-%m-%d %H:%M:%S') except (ValueError, AttributeError): pass return value
jsonstr = '{"a":10,"b":"2020-12-09 18:21:34","c":[true,"test","2020-12-09 19:09:21",null],"d":{"e":16.4,"f":"2020-12-09 20:37:06"}}'
d = json.loads(jsonstr, object_hook=datetime_parser)
でも、これは JSON に記述された日付時刻が
常に、 '%Y-%m-%d %H:%M:%S' のフォーマットであることが前提である。
もう少し汎用的、状況に応じた strptime を実行できるようにしたい。
クラスとして用意し、インスタンス生成時に、状況に応じた strptime のフォーマットを
用意する。
class Datetimetool(): def __init__(self): import re self._rt = [ ( re.compile('^\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01]) (0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[0-5][0-9]):(0[0-9]|[0-5][0-9])$'), '%Y-%m-%d %H:%M:%S' ), ( re.compile('^\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])T(0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[0-5][0-9]):(0[0-9]|[0-5][0-9])$'), '%Y-%m-%dT%H:%M:%S' ), ( re.compile('^\d{4}/(0[1-9]|1[012])/(0[1-9]|[12][0-9]|3[01]) (0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[0-5][0-9]):(0[0-9]|[0-5][0-9])$'), '%Y/%m/%d %H:%M:%S' ), ( re.compile('^\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])$'), '%Y-%m-%d' ), ( re.compile('^\d{4}/(0[1-9]|1[012])/(0[1-9]|[12][0-9]|3[01])$'), '%Y/%m/%d' ), ] def datetime_parser(self, value): if isinstance(value, dict): for k,v in value.items(): value[k] = self.datetime_parser(v) elif isinstance(value, list): for i,e in enumerate(value): value[i] = self.datetime_parser(e) elif isinstance(value, str): from datetime import datetime try: for rtt in self._rt: if rtt[0].match(value): value = datetime.strptime(value, rtt[1]) break except (ValueError, AttributeError): pass return value
jsonstr = '{"a":10,"b":"2020-12-09 18:21:34","c":[true,"test","2020/12/09 19:09:21",null],"d":{"e":16.4,"f":"2020/12/11"}}'
d = json.loads(jsonstr, object_hook=Datetimetool().datetime_parser)
上の datetime_parser メソッドですが、
文字列で日付時刻に変換を試す部分、以下は、
elif isinstance(value, str): from datetime import datetime try: for rtt in self._rt: if rtt[0].match(value): value = datetime.strptime(value, rtt[1]) break except (ValueError, AttributeError): pass
以下のように、書いた方が良いのかもしれません。
elif isinstance(value, str): from datetime import datetime try: dlst = [datetime.strptime(value, rtt[1]) for rtt in self._rt if rtt[0].match(value)] if len(dlst) > 0: value = dlst[0] except (ValueError, AttributeError): pass