JSONデシリアライズで、datetime オブジェクトにする。

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