我有一个基本的词典如下:
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
。
答案 0 :(得分:402)
基于其他答案,基于特定序列化程序的简单解决方案,只需将datetime.datetime
和datetime.date
个对象转换为字符串。
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))
如图所示,代码只是检查对象是否属于类datetime.datetime
或datetime.date
,然后使用.isoformat()
生成它的序列化版本,根据ISO 8601格式,YYYY-MM-DDTHH:MM:SS(可以通过JavaScript轻松解码)。如果寻求更复杂的序列化表示,可以使用其他代码而不是str()(例如,参见该问题的其他答案)。代码以引发异常结束,以处理使用非可序列化类型调用的情况。
这个json_serial函数可以按如下方式使用:
from datetime import datetime
from json import dumps
print dumps(datetime.now(), default=json_serial)
有关json.dumps默认参数如何工作的详细信息,请参见Section Basic Usage of the json module documentation。
答案 1 :(得分:381)
我的快速&吃掉日期和所有内容的脏JSON转储:
json.dumps(my_dictionary, indent=4, sort_keys=True, default=str)
答案 2 :(得分:292)
最初的答案符合MongoDB“date”字段的表示方式:
{"$date": 1506816000000}
如果你想要一个通用的Python解决方案来将datetime
序列化为json,请查看@jjmontes' answer以获得一个不需要依赖的快速解决方案。
当您使用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提供了一个原生的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
和使用这样的自定义default
之间注意到了一个区别:
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
所以,在某些情况下你可能需要小心。
答案 3 :(得分:183)
我刚遇到这个问题,我的解决方案是子类json.JSONEncoder
:
from datetime import datetime
import json
class DateTimeEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, datetime):
return o.isoformat()
return json.JSONEncoder.default(self, o)
在您的通话中执行以下操作:json.dumps(yourobj, cls=DateTimeEncoder)
我从上述答案中获得.isoformat()
。
答案 4 :(得分:114)
将日期转换为字符串
sample['somedate'] = str( datetime.utcnow() )
答案 5 :(得分:77)
对于那些不需要或不想使用pymongo库的人来说,你可以使用这个小片段轻松实现datetime JSON转换:
def default(obj):
"""Default JSON serializer."""
import calendar, datetime
if isinstance(obj, datetime.datetime):
if obj.utcoffset() is not None:
obj = obj - obj.utcoffset()
millis = int(
calendar.timegm(obj.timetuple()) * 1000 +
obj.microsecond / 1000
)
return millis
raise TypeError('Not sure how to serialize %s' % (obj,))
然后像这样使用它:
import datetime, json
print json.dumps(datetime.datetime.now(), default=default)
输出:
'1365091796124'
答案 6 :(得分:35)
这是我的解决方案:
# -*- coding: utf-8 -*-
import json
class DatetimeEncoder(json.JSONEncoder):
def default(self, obj):
try:
return super(DatetimeEncoder, obj).default(obj)
except TypeError:
return str(obj)
然后你可以这样使用它:
json.dumps(dictionnary, cls=DatetimeEncoder)
答案 7 :(得分:20)
我有一个类似问题的申请;我的方法是将日期时间值JSONize为6项列表(年,月,日,小时,分钟,秒);你可以将微秒作为一个7项目列表,但我没有必要:
class DateTimeEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime.datetime):
encoded_object = list(obj.timetuple())[0:6]
else:
encoded_object =json.JSONEncoder.default(self, obj)
return encoded_object
sample = {}
sample['title'] = "String"
sample['somedate'] = datetime.datetime.now()
print sample
print json.dumps(sample, cls=DateTimeEncoder)
产生
{'somedate': datetime.datetime(2013, 8, 1, 16, 22, 45, 890000), 'title': 'String'}
{"somedate": [2013, 8, 1, 16, 22, 45], "title": "String"}
答案 8 :(得分:17)
这个Q一次又一次地重复 - 一种修补json模块的简单方法,使序列化支持日期时间。
from scipy.special import expit as sigmoid
比你经常使用json序列化 - 这次将datetime序列化为isoformat。
import json
import datetime
json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)
导致:'{“created”:“2015-08-26T14:21:31.853855”}'
在以下位置查看更多详细信息和一些注意事项: StackOverflow: JSON datetime between Python and JavaScript
答案 9 :(得分:16)
我的解决方案(我认为不那么详细):
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"}'
我想要,稍后您可以通过default
方法的简单转换添加其他特殊情况。示例:
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)
答案 10 :(得分:10)
这是一个简单的解决方案来实现“datetime而不是JSON可序列化” 问题。
enco = lambda obj: (
obj.isoformat()
if isinstance(obj, datetime.datetime)
or isinstance(obj, datetime.date)
else None
)
json.dumps({'date': datetime.datetime.now()}, default=enco)
输出: - > {“date”:“2015-12-16T04:48:20.024609”}
答案 11 :(得分:8)
您必须提供cls
参数json.dumps
的自定义编码器类。引用docs:
>>> import json
>>> class ComplexEncoder(json.JSONEncoder):
... def default(self, obj):
... if isinstance(obj, complex):
... return [obj.real, obj.imag]
... return json.JSONEncoder.default(self, obj)
...
>>> dumps(2 + 1j, cls=ComplexEncoder)
'[2.0, 1.0]'
>>> ComplexEncoder().encode(2 + 1j)
'[2.0, 1.0]'
>>> list(ComplexEncoder().iterencode(2 + 1j))
['[', '2.0', ', ', '1.0', ']']
这使用复数作为示例,但您可以轻松创建一个类来编码日期(除了我认为JSON对日期有点模糊)
答案 12 :(得分:7)
您应该使用.strftime()
方法.datetime.now()
方法将其作为可序列化方法。
以下是一个例子:
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'}
答案 13 :(得分:6)
json.dumps方法可以接受称为default的可选参数,该参数应为函数。每次JSON尝试转换值时,它都不知道如何转换将调用我们传递给它的函数。该函数将接收有问题的对象,并期望返回该对象的JSON表示形式。
def myconverter(o):
if isinstance(o, datetime.datetime):
return o.__str__()
print(json.dumps(d, default = myconverter))
答案 14 :(得分:5)
最简单的方法是将日期时间格式的dict部分更改为isoformat。该值实际上是isoformat中的字符串,json可以使用。
v_dict = version.dict()
v_dict['created_at'] = v_dict['created_at'].isoformat()
答案 15 :(得分:5)
如果您使用的是python3.7,那么最好的解决方案是使用
datetime.isoformat()
和
datetime.fromisoformat()
;他们天真地和
感知datetime
对象:
#!/usr/bin/env python3.7
from datetime import datetime
from datetime import timezone
from datetime import timedelta
import json
def default(obj):
if isinstance(obj, datetime):
return { '_isoformat': obj.isoformat() }
return super().default(obj)
def object_hook(obj):
_isoformat = obj.get('_isoformat')
if _isoformat is not None:
return datetime.fromisoformat(_isoformat)
return obj
if __name__ == '__main__':
#d = { 'now': datetime(2000, 1, 1) }
d = { 'now': datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=-8))) }
s = json.dumps(d, default=default)
print(s)
print(d == json.loads(s, object_hook=object_hook))
输出:
{"now": {"_isoformat": "2000-01-01T00:00:00-08:00"}}
True
如果您使用的是python3.6或更低版本,则只关心时间值(不关心
时区),那么您可以使用datetime.timestamp()
和
datetime.fromtimestamp()
代替;
如果您使用的是python3.6或更低版本,并且确实关心时区,那么
您可以通过datetime.tzinfo
来获取,但是您必须序列化该字段
自己一个人最简单的方法是在该字段中添加另一个字段_tzinfo
序列化的对象;
最后,请注意所有这些示例中的精度;
答案 16 :(得分:3)
如果您在视图中使用结果,请务必返回正确的响应。根据API,jsonify执行以下操作:
使用给定参数的JSON表示创建Response 应用程序/ json mimetype。
要使用json.dumps模仿此行为,您必须添加一些额外的代码行。
response = make_response(dumps(sample, cls=CustomEncoder))
response.headers['Content-Type'] = 'application/json'
response.headers['mimetype'] = 'application/json'
return response
你还应该返回一个dict来完全复制jsonify的响应。所以,整个文件看起来像这样
from flask import make_response
from json import JSONEncoder, dumps
class CustomEncoder(JSONEncoder):
def default(self, obj):
if set(['quantize', 'year']).intersection(dir(obj)):
return str(obj)
elif hasattr(obj, 'next'):
return list(obj)
return JSONEncoder.default(self, obj)
@app.route('/get_reps/', methods=['GET'])
def get_reps():
sample = ['some text', <datetime object>, 123]
response = make_response(dumps({'result': sample}, cls=CustomEncoder))
response.headers['Content-Type'] = 'application/json'
response.headers['mimetype'] = 'application/json'
return response
答案 17 :(得分:3)
以下是将datetime转换为JSON并返回的完整解决方案..
import calendar, datetime, json
def outputJSON(obj):
"""Default JSON serializer."""
if isinstance(obj, datetime.datetime):
if obj.utcoffset() is not None:
obj = obj - obj.utcoffset()
return obj.strftime('%Y-%m-%d %H:%M:%S.%f')
return str(obj)
def inputJSON(obj):
newDic = {}
for key in obj:
try:
if float(key) == int(float(key)):
newKey = int(key)
else:
newKey = float(key)
newDic[newKey] = obj[key]
continue
except ValueError:
pass
try:
newDic[str(key)] = datetime.datetime.strptime(obj[key], '%Y-%m-%d %H:%M:%S.%f')
continue
except TypeError:
pass
newDic[str(key)] = obj[key]
return newDic
x = {'Date': datetime.datetime.utcnow(), 34: 89.9, 12.3: 90, 45: 67, 'Extra': 6}
print x
with open('my_dict.json', 'w') as fp:
json.dump(x, fp, default=outputJSON)
with open('my_dict.json') as f:
my_dict = json.load(f, object_hook=inputJSON)
print my_dict
输出
{'Date': datetime.datetime(2013, 11, 8, 2, 30, 56, 479727), 34: 89.9, 45: 67, 12.3: 90, 'Extra': 6}
{'Date': datetime.datetime(2013, 11, 8, 2, 30, 56, 479727), 34: 89.9, 45: 67, 12.3: 90, 'Extra': 6}
JSON文件
{"Date": "2013-11-08 02:30:56.479727", "34": 89.9, "45": 67, "12.3": 90, "Extra": 6}
这使我能够导入和导出字符串,整数,浮点数和日期时间对象。 它不应该难以扩展到其他类型。
答案 18 :(得分:2)
将date
转换为string
date = str(datetime.datetime(somedatetimehere))
答案 19 :(得分:2)
根据@jjmontes 的回答,我使用了以下方法。 对于flask 和flask-restful 用户
# get json string
jsonStr = json.dumps(my_dictionary, indent=1, sort_keys=True, default=str)
# then covert json string to json object
return json.loads(jsonStr)
答案 20 :(得分:2)
实际上,这很简单。 如果您需要经常序列化日期,则将它们作为字符串使用。您可以根据需要轻松地将它们转换回日期时间对象。
如果您需要主要用作日期时间对象,则在序列化之前将它们转换为字符串。
import json, datetime
date = str(datetime.datetime.now())
print(json.dumps(date))
"2018-12-01 15:44:34.409085"
print(type(date))
<class 'str'>
datetime_obj = datetime.datetime.strptime(date, '%Y-%m-%d %H:%M:%S.%f')
print(datetime_obj)
2018-12-01 15:44:34.409085
print(type(datetime_obj))
<class 'datetime.datetime'>
如您所见,两种情况下的输出都是相同的。只是类型不同。
答案 21 :(得分:2)
尝试使用一个示例来解析它:
#!/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()
答案 22 :(得分:2)
通常有几种方法可以序列化日期时间,例如:
如果您对最后一种方式没问题,json_tricks包会处理日期,时间和日期时间,包括时区。
from datetime import datetime
from json_tricks import dumps
foo = {'title': 'String', 'datetime': datetime(2012, 8, 8, 21, 46, 24, 862000)}
dumps(foo)
给出:
{"title": "String", "datetime": {"__datetime__": null, "year": 2012, "month": 8, "day": 8, "hour": 21, "minute": 46, "second": 24, "microsecond": 862000}}
所以你需要做的就是
`pip install json_tricks`
然后从json_tricks
而不是json
导入。
在解码时不会将其存储为单个字符串,int或float的优点:如果您只遇到一个字符串或特别是int或float,您需要了解一些有关数据的信息,以了解它是否为日期时间。作为一个字典,您可以存储元数据,以便自动解码,这是json_tricks
为您所做的。它也很容易为人类编辑。
免责声明:它是由我制作的。因为我有同样的问题。
答案 23 :(得分:1)
我的解决方案......
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
答案 24 :(得分:1)
如果您处于交流的两面,则可以使用 repr()和 eval()函数以及json。
Public Sub TestMe()
Dim c25 As String
c25 = "D10"
Range("B2").Formula = "=B9*'Master Trainings'!" & c25
End Sub
您不应将日期时间导入为
import datetime, json
dt = datetime.datetime.now()
print("This is now: {}".format(dt))
dt1 = json.dumps(repr(dt))
print("This is serialised: {}".format(dt1))
dt2 = json.loads(dt1)
print("This is loaded back from json: {}".format(dt2))
dt3 = eval(dt2)
print("This is the same object as we started: {}".format(dt3))
print("Check if they are equal: {}".format(dt == dt3))
因为eval会抱怨。或者,您可以将datetime作为参数传递给eval。无论如何,这都行得通。
答案 25 :(得分:1)
如果您想要自己的格式,可以快速修复
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)
答案 26 :(得分:1)
在使用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(),
...
答案 27 :(得分:0)
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
答案 28 :(得分:0)
当将django模型对象外部化为转储为JSON时,我遇到了同样的问题。 以下是解决问题的方法。
def externalize(model_obj):
keys = model_obj._meta.get_all_field_names()
data = {}
for key in keys:
if key == 'date_time':
date_time_obj = getattr(model_obj, key)
data[key] = date_time_obj.strftime("%A %d. %B %Y")
else:
data[key] = getattr(model_obj, key)
return data
答案 29 :(得分:0)
该库superjson可以做到。您可以按照以下说明https://superjson.readthedocs.io/index.html#extend为自己的Python对象轻松自定义json序列化程序。
一般概念是:
您的代码需要基于python对象找到正确的序列化/反序列化方法。通常,完整的类名是一个很好的标识符。
然后您的ser / deser方法应该能够将您的对象转换为常规的Json可序列化对象,该对象是通用python类型,dict,list,string,int,float的组合。然后反向实现您的deser方法。
答案 30 :(得分:0)
我今天遇到这个问题,发现了一个叫做pickle
的东西。这是一个内置库,用于序列化python对象,还可以从pickle文件中加载它。
我发现pickle
和json
之间的唯一区别是pickle
文件是二进制文件,而json
是普通的文本文件。
而且它不会导致日期时间对象出现任何问题。
答案 31 :(得分:-1)
我可能不是100%正确但是, 这是进行序列化的简单方法
#!/usr/bin/python
import datetime,json
sampledict = {}
sampledict['a'] = "some string"
sampledict['b'] = datetime.datetime.now()
print sampledict # output : {'a': 'some string', 'b': datetime.datetime(2017, 4, 15, 5, 15, 34, 652996)}
#print json.dumps(sampledict)
'''
output :
Traceback (most recent call last):
File "./jsonencodedecode.py", line 10, in <module>
print json.dumps(sampledict)
File "/usr/lib/python2.7/json/__init__.py", line 244, in dumps
return _default_encoder.encode(obj)
File "/usr/lib/python2.7/json/encoder.py", line 207, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencode
return _iterencode(o, 0)
File "/usr/lib/python2.7/json/encoder.py", line 184, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: datetime.datetime(2017, 4, 15, 5, 16, 17, 435706) is not JSON serializable
'''
sampledict['b'] = datetime.datetime.now().strftime("%B %d, %Y %H:%M %p")
afterdump = json.dumps(sampledict)
print afterdump #output : {"a": "some string", "b": "April 15, 2017 05:18 AM"}
print type(afterdump) #<type 'str'>
afterloads = json.loads(afterdump)
print afterloads # output : {u'a': u'some string', u'b': u'April 15, 2017 05:18 AM'}
print type(afterloads) # output :<type 'dict'>
答案 32 :(得分:-1)
简单
str(date_variable_here)