如何克服“datetime.datetime不JSON序列化”?
我有一个基本的字典,如下所示:
sample = {} sample['title'] = "String" sample['somedate'] = somedatetimehere
当我尝试做jsonify(sample)
我得到:
TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) is not JSON serializable
我能做些什么,使我的字典样本可以克服上面的错误?
注意:尽pipe可能不相关,但是当我打印出str(sample['somedate'])
,通过从mongodb中检索logging来生成字典,输出是2012-08-08 21:46:24.862000
。
正如你正在使用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)
基于其他答案,一个简单的解决scheme基于一个特定的序列化器,只是将datetime.datetime
和datetime.date
对象转换为string。
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()(有关示例,请参阅此问题的其他答案)。 代码通过引发exception结束,以处理用非序列化types调用的情况。
这个json_serial函数可以使用如下:
from datetime import datetime from json import dumps print dumps(datetime.now(), default=json_serial)
有关json.dumps的默认参数如何工作的细节可以在json模块文档的基本用法部分find。
将date转换为string
sample['somedate'] = str( datetime.now() )
我刚刚遇到了这个问题,我的解决scheme是子类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()
我从上面的答案之一。
我快速和肮脏的JSON转储吃date和一切:
json.dumps(my_dictionary, indent=4, sort_keys=True, default=str)
对于其他不需要或不想使用pymongo库的人来说,你可以通过这个小代码轻松实现date时间的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'
这是我的解决scheme:
# -*- 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)
我有一个类似的问题的应用程序; 我的做法是将date时间值JSON化为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"}
我的解决scheme(不太详细,我认为):
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)
这个Q重复一次又一次 – 一个简单的方法来修补json模块,以便序列化支持date时间。
import json import datetime json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)
像你一样使用json序列化 – 这次datetime被序列化为isoformat。
json.dumps({'created':datetime.datetime.now()})
导致:“{”created“:”2015-08-26T14:21:31.853855“}'
看到更多的细节和一些谨慎的话: StackOverflow:Python和JavaScript之间的JSONdate时间
这里是一个简单的解决办法来“date时间不是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”}
您必须使用json.dumps
的cls
参数提供自定义的编码器类。 引用文件 :
>>> 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', ']']
这使用复数作为例子,但你可以很容易地创build一个类来编码date(除了我认为JSON是有点模糊的date)
最简单的方法是将date时间格式的字典部分更改为isoformat。 这个值实际上是json可以使用的isoformat中的一个string。
v_dict = version.dict() v_dict['created_at'] = v_dict['created_at'].isoformat()
这里是我的date时间转换为JSON和返回的完整解决scheme..
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}
这使我能够导入和导出string,整数,浮点数和date时间对象。 其他types不应该很难延伸。
如果您在视图中使用结果,请确保返回正确的响应。 根据API,jsonify执行以下操作:
使用application / json mimetype给定参数的JSON表示创build响应。
为了用json.dumps模拟这种行为,你必须添加一些额外的代码行。
response = make_response(dumps(sample, cls=CustomEncoder)) response.headers['Content-Type'] = 'application/json' response.headers['mimetype'] = 'application/json' return response
你也应该返回一个字典来完整地复制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
我的解决scheme
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
好的,现在进行一些testing。
# 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
在使用sqlalchemy的类中编写serialize装饰器时,我得到了同样的错误信息。 所以,而不是:
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(), ...
将date
转换为string
date = str(datetime.datetime(somedatetimehere))
如果你想要自己的格式,可以快速修复
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)
通常有几种方法来序列化date时间,如:
- ISOstring,简短,可以包括时区信息,例如@ jgbarah的答案
- 时间戳(时区数据丢失),例如@ JayTaylor的答案
- 属性字典(包括时区)。
如果你没有问题, json_tricks包处理包括时区在内的date,时间和date时间。
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
导入。
解码时不会将其存储为单个string,int或float的优点:如果只遇到一个string,或者特别是int或float,则需要了解有关数据的一些信息以确定它是否是date时间。 作为一个字典,你可以存储元数据,所以它可以被自动解码,这是json_tricks
为你做的。 它也很容易编辑人类。
免责声明:由我制作。 因为我有同样的问题。
将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
要么在MySQL中以及在python代码json中作为String或date或datetime。 它为我工作,因为我将mysqltypes转换为string。
我的解决scheme只是使用EPOCH时间(这是一个数字),因为我的用例不需要最终用户在JSON中读取时间。 与时代一起工作是非常容易的。
我可能不会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'>
你应该使用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: {'a': 1, 'b': 2, 'time': '2017-10-31T15:16:30'}