如何克服“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.datetimedatetime.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.datetimedatetime.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.dumpscls参数提供自定义的编码器类。 引用文件 :

 >>> 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时间,如:

  1. ISOstring,简短,可以包括时区信息,例如@ jgbarah的答案
  2. 时间戳(时区数据丢失),例如@ JayTaylor的答案
  3. 属性字典(包括时区)。

如果你没有问题, 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'}