如何克服“datetime.datetimeJSON不可序列化”?

我有一个基本的判断如下:

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

972882 次浏览

2018年更新

最初的答案适应了MongoDB“date”字段的表示方式:

{"$date": 1506816000000}

如果您想要将datetime序列化为json的通用Python解决方案,请查看@jjmontes以获取不需要依赖项的快速解决方案。


由于您使用的是mongoEngine(每条评论)并且pymongo是一个依赖项,pymongo有内置的实用程序来帮助json序列化:
http://api.mongodb.org/python/1.10.1/api/bson/json_util.html

示例用法(序列化):

from bson import json_utilimport 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 datetimeimport 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

在某些情况下,你可能需要小心。

将日期转换为字符串

sample['somedate'] = str( datetime.utcnow() )

您必须提供一个带有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', ']']

这使用复数作为示例,但您可以轻松创建一个类来编码日期(除了我认为JSON对日期有点模糊)

对于那些不需要或不想为此使用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 millisraise TypeError('Not sure how to serialize %s' % (obj,))

然后像这样使用它:

import datetime, jsonprint json.dumps(datetime.datetime.now(), default=default)

输出:

'1365091796124'

以下是我的解决方案:

import json

class DatetimeEncoder(json.JSONEncoder):def default(self, obj):try:return super().default(obj)except TypeError:return str(obj)

然后你可以这样使用它:

json.dumps(dictionnary, cls=DatetimeEncoder)

如果您在视图中使用结果,请确保返回正确的响应。根据API,jsonify执行以下操作:

使用给定参数的JSON表示创建响应使用应用程序/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_responsefrom 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

我在将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

我的解决方案(不那么冗长,我想):

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)

我有一个类似问题的应用程序;我的方法是将datetime值JSONize6项列表(年,月,日,小时,分钟,秒);您可以将微秒作为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 sampleprint 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"}

这是我将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]continueexcept ValueError:pass
try:newDic[str(key)] = datetime.datetime.strptime(obj[key], '%Y-%m-%d %H:%M:%S.%f')continueexcept 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}

这使我能够导入和导出字符串、整数、浮点数和日期时间对象。它应该不难扩展到其他类型。

在其他答案的基础上,一个基于特定序列化器的简单解决方案,该序列化器仅将datetime.datetimedatetime.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 datetimefrom json import dumps
print dumps(datetime.now(), default=json_serial)

有关json.dumps默认参数如何工作的详细信息可以在节json模块留档的基本用法中找到。

我刚刚遇到这个问题,我的解决方案是子类json.JSONEncoder

from datetime import datetimeimport 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()

最简单的方法是将datetime格式的字典部分更改为iso格式。该值将有效地是一个iso格式的字符串,json可以使用。

v_dict = version.dict()v_dict['created_at'] = v_dict['created_at'].isoformat()

这个Q一次又一次地重复——这是修补json模块的一种简单方法,这样序列化就会支持datetime。

import jsonimport datetime
json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)

而不是像往常一样使用json序列化——这次datetime被序列化为iso格式。

json.dumps({'created':datetime.datetime.now()})

返回结果:'{"创建":"2015-08-26T14:21:31.853855"}'

查看更多细节和一些警告:StackOverflow:Python和JavaScript之间的JSON日期时间

我的解决方案…

from datetime import datetimeimport json
from pytz import timezoneimport pytz

def json_dt_serializer(obj):"""JSON serializer, by macm."""rsp = dict()if isinstance(obj, datetime):rsp['day'] = obj.dayrsp['hour'] = obj.hourrsp['microsecond'] = obj.microsecondrsp['minute'] = obj.minutersp['month'] = obj.monthrsp['second'] = obj.secondrsp['year'] = obj.yearrsp['tzinfo'] = str(obj.tzinfo)return rspraise 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

现在,一些测试。

# Testsnow = datetime.now(pytz.utc)
# Using this solutionrsp = json_dt_serializer(now)tmp = json_dt_deserialize(rsp)assert tmp == nowassert isinstance(tmp, datetime) == Trueassert isinstance(now, datetime) == True
# using default from json.dumpstmp = json.dumps(datetime.now(pytz.utc), default=json_dt_serializer)rsp = json_dt_deserialize(tmp)assert isinstance(rsp, datetime) == True
# Lets try another timezoneeastern = 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在类中编写序列化装饰器时收到了相同的错误消息。所以而不是:

Class Puppy(Base):...@propertydef serialize(self):return { 'id':self.id,'date_birth':self.date_birth,...}

我只是借用了jgbarah使用isoform()的想法,并用isoform()附加了原始值,这样它现在看起来像:

                  ...'date_birth':self.date_birth.isoformat(),...

这里有一个简单的解决方案来克服“datetime not 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"}

date转换为string

date = str(datetime.datetime(somedatetimehere))

我的快速和肮脏的JSON转储,吃日期和一切:

json.dumps(my_dictionary, indent=4, sort_keys=True, default=str)

default是一个应用于不可序列化对象的函数。
在这种情况下,它是str,所以它只是将它不知道的所有内容转换为字符串。这对于序列化非常好,但在反序列化时(因此“快速和肮脏”)就不那么好了,因为任何东西都可能在没有警告的情况下被字符串化,例如函数或numpy数组。

一个快速修复,如果你想要自己的格式

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 herejson.dumps(sample)

通常有几种方法可以序列化日期时间,例如:

  1. ISO字符串,短且可以包含时区信息,例如@jgbarah的回答
  2. 时间戳(时区数据丢失),例如@JayTaylor的回答
  3. 属性字典(包括时区)。

如果你对最后一种方法没问题,json_tricks包处理日期、时间和日期时间,包括时区。

from datetime import datetimefrom json_tricks import dumpsfoo = {'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导入。

解码时不将其存储为单个字符串、整型或浮点数的优势在于:如果您只遇到一个字符串,或者特别是整型或浮点数,您需要了解有关数据的一些信息才能知道它是否是日期时间。作为一个字典,您可以存储元数据,以便自动解码,这就是json_tricks为您所做的。它也很容易为人类编辑。

免责声明:这是我做的。因为我有同样的问题。

我可能不是100%正确,但是,这是序列化的简单方法

#!/usr/bin/pythonimport 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 dumpsreturn _default_encoder.encode(obj)File "/usr/lib/python2.7/json/encoder.py", line 207, in encodechunks = self.iterencode(o, _one_shot=True)File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencodereturn _iterencode(o, 0)File "/usr/lib/python2.7/json/encoder.py", line 184, in defaultraise 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[0]: {'a': 1, 'b': 2, 'time': '2017-10-31T15:16:30'}

【更新】:

在Python3.7及更高版本中,您可以简单地使用.isoformat()方法:

from datetime import datetime
datetime.now().isoformat()

试试这个例子来解析它:

#!/usr/bin/env python
import datetimeimport 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_parsedprint(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()
def j_serial(o):     # self containedfrom datetime import datetime, datereturn str(o).split('.')[0] if isinstance(o, (datetime, date)) else None

使用上述实用程序:

import datetimeserial_d = j_serial(datetime.datetime.now())if serial_d:print(serial_d)  # output: 2018-02-28 02:23:15

json.dumps方法可以接受一个名为default的可选参数,它应该是一个函数。每次JSON尝试转换一个值时,它都不知道如何转换,它将调用我们传递给它的函数。该函数将接收有问题的对象,并期望返回对象的JSON表示。

def myconverter(o):if isinstance(o, datetime.datetime):return o.__str__()
print(json.dumps(d, default = myconverter))

如果您在通信的双方,您可以使用repr()ava()函数以及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

因为ava会抱怨。或者您可以将datetime作为参数传递给ava。无论如何,这应该可以工作。

如果您使用的是python3.7,那么最好的解决方案是使用#0#0;他们既天真又天真datetime对象:

#!/usr/bin/env python3.7
from datetime import datetimefrom datetime import timezonefrom datetime import timedeltaimport json
def default(obj):if isinstance(obj, datetime):return { '_isoformat': obj.isoformat() }raise TypeError('...')
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获取它,但您必须序列化此字段您自己;最简单的方法是在序列化对象;

最后,要注意所有这些例子中的精确性;

其实很简单。如果您需要经常序列化日期,请将它们作为字符串使用。如果需要,您可以轻松地将它们转换回datetime对象。

如果您需要主要作为datetime对象工作,请在序列化之前将它们转换为字符串。

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.409085print(type(datetime_obj))<class 'datetime.datetime'>

如您所见,两种情况下的输出都是相同的。只有类型不同。

我今天遇到了这个问题,我发现了一个叫做pickle的东西。它是一个用于序列化python对象的内置库,也可以从泡菜文件加载它。

我发现picklejson之间的唯一区别是pickle文件是二进制文件,其中json是通常的文本文件。

并且它不会导致日期时间对象的任何问题。

根据@jjmontes的回答,我使用了以下方法。对于烧瓶和烧瓶RESTful用户

# get json stringjsonStr = json.dumps(my_dictionary, indent=1, sort_keys=True, default=str)# then covert json string to json objectreturn json.loads(jsonStr)

我通常使用#0。不仅因为其巨大的性能,还因为#1的强大(RFC-3339兼容)支持

import orjson # via pip3 install orjsonfrom datetime import datetime
data = {"created_at": datetime(2022, 3, 1)}
orjson.dumps(data) # returns b'{"created_at":"2022-03-01T00:00:00"}'

如果您想使用不带tzinfo的datetime.datetime对象作为UTC,您可以添加相关选项:

orjson.dumps(data, option=orjson.OPT_NAIVE_UTC) # returns b'{"created_at":"2022-03-01T00:00:00+00:00"}'

如果您正在使用django模型,您可以直接将encoder=DjangoJSONEncoder传递给字段构造函数。它会像魅力一样工作。

from django.core.serializers.json import DjangoJSONEncoderfrom django.db import modelsfrom 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)

另一种方法是采用DMN(决策模型符号)中定义的FEEL(足够友好的表达式语言)的概念-即@字符串。任何以@“”开头并以“”结尾的字符串都将通过FEEL解码单独解码。当然,发送者和接收者必须同意这个约定,但是……下面的代码允许您对许多其他事物以及日期、时间、日期/时间、时间增量进行编码。您可以对年/月持续时间和范围进行编码(只要您除了chr、exr、exr、chr的4元素元组是范围的良好表示-其中两个chr是开/闭括号)。因此,@“P4Y2M”是4年2个月的持续时间。@“P2DT5H”是2天4小时的时间增量,@“(2021-01-02…2021-12-31)”是一年的范围。

以下代码可用于序列化和反序列化@字符串。

import datetimeimport pySFeel
parser = pySFeel.SFeelParser()

def convertAtString(thisString):# Convert an @string(status, newValue) = parser.sFeelParse(thisString[2:-1])if 'errors' in status:return thisStringelse:return newValue

def convertIn(newValue):if isinstance(newValue, dict):for key in newValue:if isinstance(newValue[key], int):newValue[key] = float(newValue[key])elif isinstance(newValue[key], str) and (newValue[key][0:2] == '@"') and (newValue[key][-1] == '"'):newValue[key] = convertAtString(newValue[key])elif isinstance(newValue[key], dict) or isinstance(newValue[key], list):newValue[key] = convertIn(newValue[key])elif isinstance(newValue, list):for i in range(len(newValue)):if isinstance(newValue[i], int):newValue[i] = float(newValue[i])elif isinstance(newValue[i], str) and (newValue[i][0:2] == '@"') and (newValue[i][-1] == '"'):newValue[i] = convertAtString(newValue[i])elif isinstance(newValue[i], dict) or isinstance(newValue[i], list):newValue[i] = convertIn(newValue[i])elif isinstance(newValue, str) and (newValue[0:2] == '@"') and (newValue[-1] == '"'):newValue = convertAtString(newValue)return newValue

def convertOut(thisValue):if isinstance(thisValue, datetime.date):return '@"' + thisValue.isoformat() + '"'elif isinstance(thisValue, datetime.datetime):return '@"' + thisValue.isoformat(sep='T') + '"'elif isinstance(thisValue, datetime.time):return '@"' + thisValue.isoformat() + '"'elif isinstance(thisValue, datetime.timedelta):sign = ''duration = thisValue.total_seconds()if duration < 0:duration = -durationsign = '-'secs = duration % 60duration = int(duration / 60)mins = duration % 60duration = int(duration / 60)hours = duration % 24days = int(duration / 24)return '@"%sP%dDT%dH%dM%fS"' % (sign, days, hours, mins, secs)elif isinstance(thisValue, bool):return thisValue:elif thisValue is None:return thisValue:elif isinstance(thisValue, int):sign = ''if thisValue < 0:thisValue = -thisValuesign = '-'years = int(thisValue / 12)months = (thisValue % 12)return '@"%sP%dY%dM"' % (sign, years, months)elif isinstance(thisValue, tuple) and (len(thisValue) == 4):(lowEnd, lowVal, highVal, highEnd) = thisValuereturn '@"' + lowEnd + str(lowVal) + ' .. ' + str(highVal) + highEndelif thisValue is None:return 'null'elif isinstance(thisValue, dict):for item in thisValue:thisValue[item] = convertOut(thisValue[item])return thisValueelif isinstance(thisValue, list):for i in range(len(thisValue)):thisValue[i] = convertOut(thisValue[i])return thisValueelse:return thisValue