如何使用JSON.loads转换为Python datetime对象?

51 投票
13 回答
57775 浏览
提问于 2025-04-17 09:52

我有一个字符串,它表示一个JSON对象。

dumped_dict = '{"debug": false, "created_at": "2020-08-09T11:24:20"}'

当我用这个对象调用json.loads时;

json.loads(dumped_dict)

我得到了;

{'created_at': '2020-08-09T11:24:20', 'debug': False}

这里面没有任何问题。不过,我想知道有没有办法在用json.loads转换上面的对象时,把它变成像这样的东西:

{'created_at': datetime.datetime(2020, 08, 09, 11, 24, 20), 'debug': False}

简单来说,我们能不能在调用json.loads的时候,把日期时间的字符串转换成真正的datetime.datetime对象?

相关问题:

13 个回答

9

虽然从技术上讲,给一个对象钩子函数是可以工作的,但我建议使用一个合适的 JSONDecoder 子类,这样做是框架开发者的本意:

class _JSONDecoder(json.JSONDecoder):
    def __init__(self, *args, **kwargs):
        json.JSONDecoder.__init__(
            self, object_hook=self.object_hook, *args, **kwargs)

    def object_hook(self, obj):
        ret = {}
        for key, value in obj.items():
            if key in {'timestamp', 'whatever'}:
                ret[key] = datetime.fromisoformat(value) 
            else:
                ret[key] = value
        return ret

为了完整起见,这里是解码器的对应部分,自定义的 JSONEncoder:

class _JSONEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, (datetime.date, datetime.datetime, pd.Timestamp)):
            return obj.isoformat()
        return json.JSONEncoder.default(obj)

它们在实际使用中看起来是这样的:

json_str = json.dumps({'timestamp': datetime.datetime.now()}, cls=_JSONEncoder)
d = json.loads(json_str, cls=_JSONDecoder)
28

你需要传入一个 object_hook。根据文档的说明:

object_hook 是一个可选的函数,它会在解码任何对象字面量(也就是字典)时被调用。这个函数的返回值会替代原来的字典。

用法如下:

import datetime
import json

def date_hook(json_dict):
    for (key, value) in json_dict.items():
        try:
            json_dict[key] = datetime.datetime.strptime(value, "%Y-%m-%dT%H:%M:%S")
        except:
            pass
    return json_dict

dumped_dict = '{"debug": false, "created_at": "2020-08-09T11:24:20"}'
loaded_dict = json.loads(dumped_dict, object_hook=date_hook)

如果你还想处理时区的问题,就得用 dateutil,而不是 strptime。

33

到目前为止,我的解决方案是:

>>> json_string = '{"last_updated": {"$gte": "Thu, 1 Mar 2012 10:00:49 UTC"}}'
>>> dct = json.loads(json_string, object_hook=datetime_parser)
>>> dct
{u'last_updated': {u'$gte': datetime.datetime(2012, 3, 1, 10, 0, 49)}}


def datetime_parser(dct):
    for k, v in dct.items():
        if isinstance(v, basestring) and re.search("\ UTC", v):
            try:
                dct[k] = datetime.datetime.strptime(v, DATE_FORMAT)
            except:
                pass
    return dct

如果你想了解更多关于使用 object_hook 的信息,可以参考这个链接:JSON 编码器和解码器

在我的情况下,json 字符串是通过对我的 REST API 发起 GET 请求得到的。这个解决方案让我可以“正确获取日期”,而不需要让客户端和用户在 JSON 中硬编码像 __date__ 这样的前缀,只要输入的字符串符合 DATE_FORMAT,格式如下:

DATE_FORMAT = '%a, %d %b %Y %H:%M:%S UTC'

这个正则表达式的模式可能还需要进一步优化

顺便提一下,如果你在想,json_string 是一个 MongoDB/PyMongo 的查询结果。

撰写回答