我有一个基本的字典如下:
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)
我通常使用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"}'
我的解决方案是……
from datetime import datetime
import json
from pytz import timezone
import pytz
def json_dt_serializer(obj):
"""JSON serializer, by macm.
"""
rsp = dict()
if isinstance(obj, datetime):
rsp['day'] = obj.day
rsp['hour'] = obj.hour
rsp['microsecond'] = obj.microsecond
rsp['minute'] = obj.minute
rsp['month'] = obj.month
rsp['second'] = obj.second
rsp['year'] = obj.year
rsp['tzinfo'] = str(obj.tzinfo)
return rsp
raise TypeError("Type not serializable")
def json_dt_deserialize(obj):
"""JSON deserialize from json_dt_serializer, by macm.
"""
if isinstance(obj, str):
obj = json.loads(obj)
tzone = timezone(obj['tzinfo'])
tmp_dt = datetime(obj['year'],
obj['month'],
obj['day'],
hour=obj['hour'],
minute=obj['minute'],
second=obj['second'],
microsecond=obj['microsecond'])
loc_dt = tzone.localize(tmp_dt)
deserialize = loc_dt.astimezone(tzone)
return deserialize
好,现在来做一些测试。
# Tests
now = datetime.now(pytz.utc)
# Using this solution
rsp = json_dt_serializer(now)
tmp = json_dt_deserialize(rsp)
assert tmp == now
assert isinstance(tmp, datetime) == True
assert isinstance(now, datetime) == True
# using default from json.dumps
tmp = json.dumps(datetime.now(pytz.utc), default=json_dt_serializer)
rsp = json_dt_deserialize(tmp)
assert isinstance(rsp, datetime) == True
# Lets try another timezone
eastern = timezone('US/Eastern')
now = datetime.now(eastern)
rsp = json_dt_serializer(now)
tmp = json_dt_deserialize(rsp)
print(tmp)
# 2015-10-22 09:18:33.169302-04:00
print(now)
# 2015-10-22 09:18:33.169302-04:00
# Wow, Works!
assert tmp == now
我的解决方案(我认为不那么冗长):
def default(o):
if type(o) is datetime.date or type(o) is datetime.datetime:
return o.isoformat()
def jsondumps(o):
return json.dumps(o, default=default)
然后使用jsondumps而不是json.dumps。它将打印:
>>> jsondumps({'today': datetime.date.today()})
'{"today": "2013-07-30"}'
如果你想,以后你可以添加其他特殊情况,通过一个简单的默认方法。例子:
def default(o):
if type(o) is datetime.date or type(o) is datetime.datetime:
return o.isoformat()
if type(o) is decimal.Decimal:
return float(o)