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

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。


当前回答

如果你正在使用django模型,你可以直接将encoder=DjangoJSONEncoder传递给field构造函数。它会像魔法一样有效。

from django.core.serializers.json import DjangoJSONEncoder 
from django.db import models 
from django.utils.timezone import now


class Activity(models.Model):
    diff = models.JSONField(null=True, blank=True, encoder=DjangoJSONEncoder)


diff = {
    "a": 1,
    "b": "BB",
    "c": now()
}

Activity.objects.create(diff=diff)

其他回答

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

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

我通常使用orjson。不仅因为它出色的性能,还因为它对datetime的强大支持(符合RFC-3339):

import orjson # via pip3 install orjson
from datetime import datetime

data = {"created_at": datetime(2022, 3, 1)}

orjson.dumps(data) # returns b'{"created_at":"2022-03-01T00:00:00"}'

如果你想使用datetime。没有tzinfo作为UTC的datetime对象,您可以添加相关选项:

orjson.dumps(data, option=orjson.OPT_NAIVE_UTC) # returns b'{"created_at":"2022-03-01T00:00:00+00:00"}'

在使用sqlalchemy在类中编写序列化装饰器时,我得到了相同的错误消息。所以不要:

Class Puppy(Base):
    ...
    @property
    def serialize(self):
        return { 'id':self.id,
                 'date_birth':self.date_birth,
                  ...
                }

我只是借用了jgbarah使用isoformat()的想法,并将原始值附加到isoformat(),这样它现在看起来就像:

                  ...
                 'date_birth':self.date_birth.isoformat(),
                  ...

如果你想要自己的格式,一个快速修复

for key,val in sample.items():
    if isinstance(val, datetime):
        sample[key] = '{:%Y-%m-%d %H:%M:%S}'.format(val) #you can add different formating here
json.dumps(sample)

在其他答案的基础上,一个简单的解决方案基于只转换datetime的特定序列化器。Datetime和Datetime。将对象日期指定为字符串。

from datetime import date, datetime

def json_serial(obj):
    """JSON serializer for objects not serializable by default json code"""

    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError ("Type %s not serializable" % type(obj))

As seen, the code just checks to find out if object is of class datetime.datetime or datetime.date, and then uses .isoformat() to produce a serialized version of it, according to ISO 8601 format, YYYY-MM-DDTHH:MM:SS (which is easily decoded by JavaScript). If more complex serialized representations are sought, other code could be used instead of str() (see other answers to this question for examples). The code ends by raising an exception, to deal with the case it is called with a non-serializable type.

这个json_serial函数可以这样使用:

from datetime import datetime
from json import dumps

print dumps(datetime.now(), default=json_serial)

详细说明如何将默认参数设置为json。可以在json模块文档的基本用法章节中找到dump作品。