我有一个基本的字典如下:

sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere

当我尝试做jsonify(sample)时,我得到:

TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) is not JSON serializable

我该怎么做才能使我的字典样本克服上面的错误呢?

注意:虽然它可能不相关,字典是从mongodb的记录检索中生成的,当我打印出str(sample['somedate'])时,输出是2012-08-08 21:46:24.862000。


当前回答

您应该在.datetime.now()方法上应用.strftime()方法,使其成为一个可序列化的方法。

这里有一个例子:

from datetime import datetime

time_dict = {'time': datetime.now().strftime('%Y-%m-%dT%H:%M:%S')}
sample_dict = {'a': 1, 'b': 2}
sample_dict.update(time_dict)
sample_dict

输出:

Out[0]: {'a': 1, 'b': 2, 'time': '2017-10-31T15:16:30'}

(更新):

在Python3.7及以后版本中,你可以简单地使用.isoformat()方法:

from datetime import datetime

datetime.now().isoformat()

其他回答

我的快速和肮脏的JSON转储吃日期和一切:

json.dumps(my_dictionary, indent=4, sort_keys=True, default=str)

Default是一个应用于不可序列化对象的函数。 在这种情况下,它是str,所以它只是把所有它不知道的东西转换成字符串。这对于序列化很好,但在反序列化时就不太好了(因此是“快速和肮脏”),因为任何东西都可能在没有警告的情况下被字符串化,例如函数或numpy数组。

试着用一个例子来解析它:

#!/usr/bin/env python

import datetime
import json

import dateutil.parser  # pip install python-dateutil


class JSONEncoder(json.JSONEncoder):

    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return obj.isoformat()
        return super(JSONEncoder, self).default(obj)


def test():
    dts = [
        datetime.datetime.now(),
        datetime.datetime.now(datetime.timezone(-datetime.timedelta(hours=4))),
        datetime.datetime.utcnow(),
        datetime.datetime.now(datetime.timezone.utc),
    ]
    for dt in dts:
        dt_isoformat = json.loads(json.dumps(dt, cls=JSONEncoder))
        dt_parsed = dateutil.parser.parse(dt_isoformat)
        assert dt == dt_parsed
        print(f'{dt}, {dt_isoformat}, {dt_parsed}')
        # 2018-07-22 02:22:42.910637, 2018-07-22T02:22:42.910637, 2018-07-22 02:22:42.910637
        # 2018-07-22 02:22:42.910643-04:00, 2018-07-22T02:22:42.910643-04:00, 2018-07-22 02:22:42.910643-04:00
        # 2018-07-22 06:22:42.910645, 2018-07-22T06:22:42.910645, 2018-07-22 06:22:42.910645
        # 2018-07-22 06:22:42.910646+00:00, 2018-07-22T06:22:42.910646+00:00, 2018-07-22 06:22:42.910646+00:00


if __name__ == '__main__':
    test()
def j_serial(o):     # self contained
    from datetime import datetime, date
    return str(o).split('.')[0] if isinstance(o, (datetime, date)) else None

以上用途的使用:

import datetime
serial_d = j_serial(datetime.datetime.now())
if serial_d:
    print(serial_d)  # output: 2018-02-28 02:23:15

2018年更新

最初的答案适应了MongoDB“date”字段的表示方式:

{" $日期":1506816000000}

如果你想要一个通用的Python解决方案来将datetime序列化为json,请查看@jjmontes的答案,这是一个不需要依赖的快速解决方案。


当你在使用mongoengine(每个注释)而pymongo是一个依赖时,pymongo有内置的实用工具来帮助json序列化: http://api.mongodb.org/python/1.10.1/api/bson/json_util.html

示例用法(序列化):

from bson import json_util
import json

json.dumps(anObject, default=json_util.default)

示例用法(反序列化):

json.loads(aJsonString, object_hook=json_util.object_hook)

Django

Django提供了一个原生的DjangoJSONEncoder序列化器来正确地处理这类问题。

看到https://docs.djangoproject.com/en/dev/topics/serialization/ djangojsonencoder

from django.core.serializers.json import DjangoJSONEncoder

return json.dumps(
  item,
  sort_keys=True,
  indent=1,
  cls=DjangoJSONEncoder
)

我注意到DjangoJSONEncoder和使用自定义默认之间的一个区别:

import datetime
import json

def default(o):
    if isinstance(o, (datetime.date, datetime.datetime)):
        return o.isoformat()

return json.dumps(
  item,
  sort_keys=True,
  indent=1,
  default=default
)

Django剥离了一些数据:

 "last_login": "2018-08-03T10:51:42.990", # DjangoJSONEncoder 
 "last_login": "2018-08-03T10:51:42.990239", # default

所以,在某些情况下,你可能需要小心。

将日期转换为字符串

sample['somedate'] = str( datetime.utcnow() )