JSON datetime between Python and JavaScript
我想使用json从python发送一个序列化形式的datetime.datetime对象,并使用json在javascript中反序列化。最好的方法是什么?
您可以将"default"参数添加到json.dumps以处理此问题:
1 2 3 4 5 6 7 | date_handler = lambda obj: ( obj.isoformat() if isinstance(obj, (datetime.datetime, datetime.date)) else None ) json.dumps(datetime.datetime.now(), default=date_handler) '"2010-04-20T20:08:21.634121"' |
。
这是ISO 8601格式。
更全面的默认处理程序函数:
1 2 3 4 5 6 7 | def handler(obj): if hasattr(obj, 'isoformat'): return obj.isoformat() elif isinstance(obj, ...): return ... else: raise TypeError, 'Object of type %s with value of %s is not JSON serializable' % (type(obj), repr(obj)) |
更新:添加了类型和值的输出。更新:同时处理日期
对于跨语言项目,我发现包含RFC3339日期的字符串是最好的方法。RFC3339日期如下:
1 | 1985-04-12T23:20:50.52Z |
号
我认为大多数格式都是显而易见的。唯一有点不寻常的可能是结尾的"Z"。它代表格林尼治标准时间/UTC。您还可以为CEST(德国,夏季)添加一个时区偏移量,如+02:00。我个人更喜欢将所有内容保留在UTC中,直到显示出来。
对于显示、比较和存储,可以将其保留为所有语言的字符串格式。如果需要计算的日期,可以很容易地将其转换回大多数语言中的本机日期对象。
所以生成这样的JSON:
1 | json.dump(datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ')) |
不幸的是,JavaScript的日期构造函数不接受RFC3339字符串,但是Internet上有许多可用的解析器。
Hutools.hujson试图在正确处理时区时处理在Python代码中可能遇到的最常见的编码问题,包括日期/日期时间对象。
I've worked it out.
Let's say you have a Python datetime object, d, created with datetime.now(). Its value is:
1 | datetime.datetime(2011, 5, 25, 13, 34, 5, 787000) |
您可以将其作为ISO 8601日期时间字符串序列化为JSON:
1 2 | import json json.dumps(d.isoformat()) |
。
示例datetime对象将序列化为:
1 | '"2011-05-25T13:34:05.787000"' |
在javascript层中接收到该值后,可以构造一个日期对象:
1 | var d = new Date("2011-05-25T13:34:05.787000"); |
。
从javascript 1.8.5开始,日期对象有一个tojson方法,它以标准格式返回一个字符串。因此,要将上述javascript对象序列化回json,命令将是:
1 | d.toJSON() |
号
这会给你:
1 | '2011-05-25T20:34:05.787Z' |
号
此字符串一旦在python中接收到,就可以反序列化回datetime对象:
1 | datetime.strptime('2011-05-25T20:34:05.787Z', '%Y-%m-%dT%H:%M:%S.%fZ') |
号
这将产生以下datetime对象,该对象与您开始使用的对象相同,因此是正确的:
1 | datetime.datetime(2011, 5, 25, 20, 34, 5, 787000) |
号
使用
1 2 3 4 5 6 7 8 9 | import json import datetime class DateTimeJSONEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, datetime.datetime): return obj.isoformat() else: return super(DateTimeJSONEncoder, self).default(obj) |
。
然后,你可以这样称呼它:
1 2 | >>> DateTimeJSONEncoder().encode([datetime.datetime.now()]) '["2010-06-15T14:42:28"]' |
。
这里有一个非常完整的解决方案,可以使用标准库
只有当iso日期字符串是javascript中的值时,解码才有效。文本对象表示法或在对象内的嵌套结构中。ISO日期作为顶级数组项的字符串将不会被解码。
即,本工程:
1 2 3 4 5 6 7 | date = datetime.datetime.now() >>> json = dumps(dict(foo='bar', innerdict=dict(date=date))) >>> json '{"innerdict": {"date":"2010-07-15T13:16:38.365579 <div class="suo-content">[collapse title=""]<ul><li>如果您像<wyn>datetime.datetime.utcnow().isoformat()[:-3]+"Z"</wyn>那样打印日期,它将与json.stringify()在javascript中生成的结果完全相同。</li></ul>[/collapse]</div><hr><P>如果您确定只有javascript会使用JSON,那么我更喜欢直接传递javascript <wyn>Date</wyn>对象。</P><P><wyn>datetime</wyn>对象上的<wyn>ctime()</wyn>方法将返回一个javascript日期对象可以理解的字符串。</P>[cc lang="javascript"]import datetime date = datetime.datetime.today() json = '{"mydate":new Date("%s")}' % date.ctime() |
Javascript很乐意将其用作对象文本,并且您已经内置了日期对象。
游戏后期…:)
一个非常简单的解决方案是修补JSON模块的默认值。例如:
1 2 3 4 | import json import datetime json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None) |
现在,您可以使用json.dumps(),就好像它一直支持datetime一样…
1 | json.dumps({'created':datetime.datetime.now()}) |
号
如果您需要对JSON模块进行此扩展以始终启动并希望不更改您或其他人使用JSON序列化的方式(无论是在现有代码中还是在现有代码中),那么这是有意义的。
请注意,有些人可能认为以这种方式修补库是一种不好的做法。如果您希望以多种方式扩展您的应用程序,则需要特别注意——在这种情况下,我建议使用Ramen或JT的解决方案,并在每种情况下选择适当的JSON扩展。
除了时间戳之外,没有什么可添加到社区wiki答案中!
javascript使用以下格式:
1 | new Date().toJSON() //"2016-01-08T19:00:00.123Z" |
python端(对于
1 2 3 4 5 6 | >>> from datetime import datetime >>> d = datetime.strptime('2016-01-08T19:00:00.123Z', '%Y-%m-%dT%H:%M:%S.%fZ') >>> d datetime.datetime(2016, 1, 8, 19, 0, 0, 123000) >>> d.isoformat() + 'Z' '2016-01-08T19:00:00.123000Z' |
。
如果不使用Z,则前端框架(如Angular)无法在浏览器本地时区中显示日期:
1 2 3 4 | > $filter('date')('2016-01-08T19:00:00.123000Z', 'yyyy-MM-dd HH:mm:ss') "2016-01-08 20:00:00" > $filter('date')('2016-01-08T19:00:00.123000', 'yyyy-MM-dd HH:mm:ss') "2016-01-08 19:00:00" |
我的建议是使用图书馆。在pypi.org上有几个。
我用这个,它很好用:https://pypi.python.org/pypi/asjson
在python方面:
1 2 3 4 5 | import time, json from datetime import datetime as dt your_date = dt.now() data = json.dumps(time.mktime(your_date.timetuple())*1000) return data # data send to javascript |
号
在javascript方面:
1 | var your_date = new Date(data) |
号
其中数据来自python
显然,"正确"的json(well javascript)日期格式是2012-04-23t18:25:43.511z-utc和"z"。如果没有此javascript,则在从字符串创建日期()对象时,将使用Web浏览器的本地时区。
对于"幼稚"的时间(python称之为没有时区的时间,并假定为本地时间),下面将强制本地时区,以便将其正确转换为UTC:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | def default(obj): if hasattr(obj,"json") and callable(getattr(obj,"json")): return obj.json() if hasattr(obj,"isoformat") and callable(getattr(obj,"isoformat")): # date/time objects if not obj.utcoffset(): # add local timezone to"naive" local time # https://stackoverflow.com/questions/2720319/python-figure-out-local-timezone tzinfo = datetime.now(timezone.utc).astimezone().tzinfo obj = obj.replace(tzinfo=tzinfo) # convert to UTC obj = obj.astimezone(timezone.utc) # strip the UTC offset obj = obj.replace(tzinfo=None) return obj.isoformat() +"Z" elif hasattr(obj,"__str__") and callable(getattr(obj,"__str__")): return str(obj) else: print("obj:", obj) raise TypeError(obj) def dump(j, io): json.dump(j, io, indent=2, default=default) |
。
为什么这么难。