问题:如何克服“ 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
我该怎么做才能使我的字典示例可以克服上述错误?
注意:尽管可能无关紧要,但字典是从记录的检索中生成的,这些记录是mongodb
在我打印出str(sample['somedate'])
的地方输出的2012-08-08 21:46:24.862000
。
I have a basic dict as follows:
sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere
When I try to do jsonify(sample)
I get:
TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) is not JSON serializable
What can I do such that my dictionary sample can overcome the error above?
Note: Though it may not be relevant, the dictionaries are generated from the retrieval of records out of mongodb
where when I print out str(sample['somedate'])
, the output is 2012-08-08 21:46:24.862000
.
回答 0
更新于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
和使用这样的自定义之间的一个区别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
因此,在某些情况下,您可能需要注意这一点。
Updated for 2018
The original answer accommodated the way MongoDB “date” fields were represented as:
{"$date": 1506816000000}
If you want a generic Python solution for serializing datetime
to json, check out @jjmontes’ answer for a quick solution which requires no dependencies.
As you are using mongoengine (per comments) and pymongo is a dependency, pymongo has built-in utilities to help with json serialization:
http://api.mongodb.org/python/1.10.1/api/bson/json_util.html
Example usage (serialization):
from bson import json_util
import json
json.dumps(anObject, default=json_util.default)
Example usage (deserialization):
json.loads(aJsonString, object_hook=json_util.object_hook)
Django
Django provides a native DjangoJSONEncoder
serializer that deals with this kind of properly.
See 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
)
One difference I’ve noticed between DjangoJSONEncoder
and using a custom default
like this:
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
)
Is that Django strips a bit of the data:
"last_login": "2018-08-03T10:51:42.990", # DjangoJSONEncoder
"last_login": "2018-08-03T10:51:42.990239", # default
So, you may need to be careful about that in some cases.
回答 1
我的快速且肮脏的JSON转储会吃掉日期和所有东西:
json.dumps(my_dictionary, indent=4, sort_keys=True, default=str)
My quick & dirty JSON dump that eats dates and everything:
json.dumps(my_dictionary, indent=4, sort_keys=True, default=str)
回答 2
基于其他答案,这是一个基于特定序列化器的简单解决方案,该序列化器仅将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默认参数如何工作的详细信息,请参见json模块文档的“基本用法”部分。
Building on other answers, a simple solution based on a specific serializer that just converts datetime.datetime
and datetime.date
objects to strings.
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.
This json_serial function can be used as follows:
from datetime import datetime
from json import dumps
print dumps(datetime.now(), default=json_serial)
The details about how the default parameter to json.dumps works can be found in Section Basic Usage of the json module documentation.
回答 3
我刚遇到这个问题,我的解决方案是子类化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()
我从上面的答案之一了。
I have just encountered this problem and my solution is to subclass 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)
In your call do something like: json.dumps(yourobj, cls=DateTimeEncoder)
The .isoformat()
I got from one of the answers above.
回答 4
将日期转换为字符串
sample['somedate'] = str( datetime.utcnow() )
Convert the date to a string
sample['somedate'] = str( datetime.utcnow() )
回答 5
对于不需要或想要使用pymongo库的其他人,您可以使用此小片段轻松实现日期时间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'
For others who do not need or want to use the pymongo library for this.. you can achieve datetime JSON conversion easily with this small snippet:
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,))
Then use it like so:
import datetime, json
print json.dumps(datetime.datetime.now(), default=default)
output:
'1365091796124'
回答 6
这是我的解决方案:
# -*- 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)
Here is my solution:
# -*- 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)
Then you can use it like that:
json.dumps(dictionnary, cls=DatetimeEncoder)
回答 7
我有一个类似问题的应用程序;我的方法是将datetime值作为6项列表(年,月,日,时,分,秒)进行JSON化;您可以将微秒作为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"}
I have an application with a similar issue; my approach was to JSONize the datetime value as a 6-item list (year, month, day, hour, minutes, seconds); you could go to microseconds as a 7-item list, but I had no need to:
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)
produces:
{'somedate': datetime.datetime(2013, 8, 1, 16, 22, 45, 890000), 'title': 'String'}
{"somedate": [2013, 8, 1, 16, 22, 45], "title": "String"}
回答 8
我的解决方案(我认为冗长程度较低):
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)
My solution (with less verbosity, I think):
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)
Then use jsondumps
instead of json.dumps
. It will print:
>>> jsondumps({'today': datetime.date.today()})
'{"today": "2013-07-30"}'
I you want, later you can add other special cases to this with a simple twist of the default
method. Example:
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)
回答 9
这个Q一次又一次地重复-修补json模块的一种简单方法,以便序列化支持datetime。
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之间的JSON日期时间
This Q repeats time and time again – a simple way to patch the json module such that serialization would support datetime.
import json
import datetime
json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)
Than use json serialization as you always do – this time with datetime being serialized as isoformat.
json.dumps({'created':datetime.datetime.now()})
Resulting in: ‘{“created”: “2015-08-26T14:21:31.853855”}’
See more details and some words of caution at:
StackOverflow: JSON datetime between Python and JavaScript
回答 10
json.dumps方法可以接受称为default的可选参数,该参数应为函数。每次JSON尝试转换值时,它都不知道如何转换将调用我们传递给它的函数。该函数将接收有问题的对象,并且应返回该对象的JSON表示形式。
def myconverter(o):
if isinstance(o, datetime.datetime):
return o.__str__()
print(json.dumps(d, default = myconverter))
The json.dumps method can accept an optional parameter called default which is expected to be a function. Every time JSON tries to convert a value it does not know how to convert it will call the function we passed to it. The function will receive the object in question, and it is expected to return the JSON representation of the object.
def myconverter(o):
if isinstance(o, datetime.datetime):
return o.__str__()
print(json.dumps(d, default = myconverter))
回答 11
如果您使用的是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
在序列化对象中添加另一个字段;
最后,在所有这些示例中都要当心精度;
if you are using python3.7, then the best solution is using
datetime.isoformat()
and
datetime.fromisoformat()
; they work with both naive and
aware datetime
objects:
#!/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))
output:
{"now": {"_isoformat": "2000-01-01T00:00:00-08:00"}}
True
if you are using python3.6 or below, and you only care about the time value (not
the timezone), then you can use datetime.timestamp()
and
datetime.fromtimestamp()
instead;
if you are using python3.6 or below, and you do care about the timezone, then
you can get it via datetime.tzinfo
, but you have to serialize this field
by yourself; the easiest way to do this is to add another field _tzinfo
in the
serialized object;
finally, beware of precisions in all these examples;
回答 12
您应使用.strftime()
method on .datetime.now()
method使其成为可序列化的方法。
这是一个例子:
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'}
You should use .strftime()
method on .datetime.now()
method to making it as a serializable method.
Here’s an example:
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
Output:
Out[0]: {'a': 1, 'b': 2, 'time': '2017-10-31T15:16:30'}
回答 13
这是解决“ datetime not JSON serializable”问题的简单解决方案。
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”}
Here is a simple solution to over come “datetime not JSON serializable”
problem.
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)
Output:-> {“date”: “2015-12-16T04:48:20.024609”}
回答 14
您必须提供一个自定义编码器类,其cls
参数为json.dumps
。引用文档:
>>> 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对日期有些模糊)
You have to supply a custom encoder class with the cls
parameter of json.dumps
. To quote from the 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', ']']
This uses complex numbers as the example, but you can just as easily create a class to encode dates (except I think JSON is a little fuzzy about dates)
回答 15
最简单的方法是将日期时间格式的字典部分更改为isoformat。该值将有效地是json可以使用的isoformat字符串。
v_dict = version.dict()
v_dict['created_at'] = v_dict['created_at'].isoformat()
The simplest way to do this is to change the part of the dict that is in datetime format to isoformat. That value will effectively be a string in isoformat which json is ok with.
v_dict = version.dict()
v_dict['created_at'] = v_dict['created_at'].isoformat()
回答 16
其实这很简单。如果您需要经常序列化日期,则将它们作为字符串使用。如果需要,您可以轻松地将它们转换回日期时间对象。
如果您主要需要用作日期时间对象,则在序列化之前将它们转换为字符串。
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'>
如您所见,两种情况下的输出是相同的。只有类型不同。
Actually it is quite simple.
If you need to often serialize dates, then work with them as strings. You can easily convert them back as datetime objects if needed.
If you need to work mostly as datetime objects, then convert them as strings before serializing.
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'>
As you can see, the output is the same in both cases. Only the type is different.
回答 17
如果在视图中使用结果,请确保返回正确的响应。根据API,jsonify执行以下操作:
创建一个带有给定参数的JSON表示的响应,该响应具有application / json mimetype。
要用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
If you are using the result in a view be sure to return a proper response. According to the API, jsonify does the following:
Creates a Response with the JSON representation of the given arguments
with an application/json mimetype.
To mimic this behavior with json.dumps you have to add a few extra lines of code.
response = make_response(dumps(sample, cls=CustomEncoder))
response.headers['Content-Type'] = 'application/json'
response.headers['mimetype'] = 'application/json'
return response
You should also return a dict to fully replicate jsonify’s response. So, the entire file will look like this
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
回答 18
尝试用一个示例来解析它:
#!/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()
Try this one with an example to parse it:
#!/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()
回答 19
我的解决方案…
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
My solution …
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
Ok, now some tests.
# 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
回答 20
这是将日期时间转换为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}
这使我能够导入和导出字符串,整数,浮点数和日期时间对象。对于其他类型,应该不难扩展。
Here is my full solution for converting datetime to JSON and back..
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
Output
{'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 File
{"Date": "2013-11-08 02:30:56.479727", "34": 89.9, "45": 67, "12.3": 90, "Extra": 6}
This has enabled me to import and export strings, ints, floats and datetime objects.
It shouldn’t be to hard to extend for other types.
回答 21
转换date
为 string
date = str(datetime.datetime(somedatetimehere))
Convert the date
to string
date = str(datetime.datetime(somedatetimehere))
回答 22
通常,有几种方法可以序列化日期时间,例如:
- ISO字符串,短,可以包含时区信息,例如@jgbarah的答案
- 时间戳记(时区数据丢失),例如@JayTaylor的答案
- 属性字典(包括时区)。
如果您对最后一种方法感到满意,则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
您需要的。它对于人类也很容易编辑。
免责声明:它是我做的。因为我有同样的问题。
Generally there are several ways to serialize datetimes, like:
- ISO string, short and can include timezone info, e.g. @jgbarah’s answer
- Timestamp (timezone data is lost), e.g. @JayTaylor’s answer
- Dictionary of properties (including timezone).
If you’re okay with the last way, the json_tricks package handles dates, times and datetimes including timezones.
from datetime import datetime
from json_tricks import dumps
foo = {'title': 'String', 'datetime': datetime(2012, 8, 8, 21, 46, 24, 862000)}
dumps(foo)
which gives:
{"title": "String", "datetime": {"__datetime__": null, "year": 2012, "month": 8, "day": 8, "hour": 21, "minute": 46, "second": 24, "microsecond": 862000}}
So all you need to do is
`pip install json_tricks`
and then import from json_tricks
instead of json
.
The advantage of not storing it as a single string, int or float comes when decoding: if you encounter just a string or especially int or float, you need to know something about the data to know if it’s a datetime. As a dict, you can store metadata so it can be decoded automatically, which is what json_tricks
does for you. It’s also easily editable for humans.
Disclaimer: it’s made by me. Because I had the same problem.
回答 23
在使用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(),
...
I got the same error message while writing the serialize decorator inside a Class with sqlalchemy. So instead of :
Class Puppy(Base):
...
@property
def serialize(self):
return { 'id':self.id,
'date_birth':self.date_birth,
...
}
I simply borrowed jgbarah’s idea of using isoformat() and appended the original value with isoformat(), so that it now looks like:
...
'date_birth':self.date_birth.isoformat(),
...
回答 24
如果需要自己的格式,可以快速解决
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)
A quick fix if you want your own formatting
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)
回答 25
如果您处于通信的两面,则可以将repr()和eval()函数与json一起使用。
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))
您不应该将datetime导入为
from datetime import datetime
因为eval会抱怨。或者,您可以将datetime作为参数传递给eval。无论如何,这都行得通。
If you are on both sides of the communication you can use repr() and eval() functions along with json.
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))
You shouldn’t import datetime as
from datetime import datetime
since eval will complain. Or you can pass datetime as a parameter to eval. In any case this should work.
回答 26
当外部化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
I had encountered same problem when externalizing django model object to dump as JSON.
Here is how you can solve it.
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
回答 27
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
def j_serial(o): # self contained
from datetime import datetime, date
return str(o).split('.')[0] if isinstance(o, (datetime, date)) else None
Usage of above utility:
import datetime
serial_d = j_serial(datetime.datetime.now())
if serial_d:
print(serial_d) # output: 2018-02-28 02:23:15
回答 28
This library superjson can do it. And you can easily custom json serializer for your own Python Object by following this instruction https://superjson.readthedocs.io/index.html#extend.
The general concept is:
your code need to locate the right serialization / deserialization method based on the python object. Usually, the full classname is a good identifier.
And then your ser / deser method should be able to transform your object to a regular Json serializable object, a combination of generic python type, dict, list, string, int, float. And implement your deser method reversely.
回答 29
我可能不是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'>
I may not 100% correct but,
this is the simple way to do serialize
#!/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'>