我想使用JSON从Python发送序列化形式的datetime.datetime对象,并使用JSON在JavaScript中反序列化.做这个的最好方式是什么?
您可以将'default'参数添加到json.dumps来处理:
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格式.
更全面的默认处理函数:
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))
更新:添加了类型和值的输出.
更新:还处理日期
对于跨语言项目,我发现包含RfC 3339日期的字符串是最好的方法.RfC 3339日期如下所示:
1985-04-12T23:20:50.52Z
我认为大部分格式都很明显.唯一有点不寻常的事情可能是最后的"Z".它代表GMT/UTC.您还可以为CEST(德国夏季)添加+02:00的时区偏移量.我个人更喜欢将所有内容保留在UTC中,直到显示为止.
对于显示,比较和存储,您可以将其保留为所有语言的字符串格式.如果您需要计算日期,则可以将其转换回大多数语言的本机日期对象.
所以生成这样的JSON:
json.dump(datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ'))
不幸的是,Javascript的Date构造函数不接受RfC 3339字符串,但Internet上有许多解析器.
huTools.hujson尝试处理Python代码中可能遇到的最常见的编码问题,包括日期/日期时间对象,同时正确处理时区.
我已经解决了.
假设您有一个使用datetime.now()创建的Python日期时间对象d.它的价值是:
datetime.datetime(2011, 5, 25, 13, 34, 5, 787000)
您可以将其序列化为JSON,作为ISO 8601日期时间字符串:
import json json.dumps(d.isoformat())
示例datetime对象将序列化为:
'"2011-05-25T13:34:05.787000"'
一旦在Javascript层中收到此值,就可以构造Date对象:
var d = new Date("2011-05-25T13:34:05.787000");
从Javascript 1.8.5开始,Date对象有一个toJSON方法,它以标准格式返回一个字符串.因此,要将上面的Javascript对象序列化回JSON,命令将是:
d.toJSON()
哪个会给你:
'2011-05-25T20:34:05.787Z'
这个字符串一旦在Python中收到,就可以反序列化回一个datetime对象:
datetime.strptime('2011-05-25T20:34:05.787Z', '%Y-%m-%dT%H:%M:%S.%fZ')
这会产生以下datetime对象,它与您开始时的对象相同,因此正确:
datetime.datetime(2011, 5, 25, 20, 34, 5, 787000)
使用json
,您可以继承JSONEncoder并覆盖default()方法以提供您自己的自定义序列化程序:
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)
然后,你可以像这样调用它:
>>> DateTimeJSONEncoder().encode([datetime.datetime.now()]) '["2010-06-15T14:42:28"]'
这是一个相当完整的解决方案,使用标准库json
模块递归编码和解码datetime.datetime和datetime.date对象.这需要Python> = 2.6,因为自那时起,%f
datetime.datetime.strptime()格式字符串中的格式代码才受支持.对于Python 2.5支持,%f
在尝试转换它之前,从ISO日期字符串中删除并剥离微秒,但当然,你将失去微秒的精度.对于与来自其他来源的ISO日期字符串的互操作性(可能包括时区名称或UTC偏移量),您可能还需要在转换之前去除日期字符串的某些部分.有关ISO日期字符串(以及许多其他日期格式)的完整解析器,请参阅第三方dateutil模块.
仅当ISO日期字符串是JavaScript文字对象表示法中的值或对象内的嵌套结构中时,解码才有效.ISO日期字符串是顶级数组的项目,不会被解码.
即这是有效的:
date = datetime.datetime.now() >>> json = dumps(dict(foo='bar', innerdict=dict(date=date))) >>> json '{"innerdict": {"date": "2010-07-15T13:16:38.365579"}, "foo": "bar"}' >>> loads(json) {u'innerdict': {u'date': datetime.datetime(2010, 7, 15, 13, 16, 38, 365579)}, u'foo': u'bar'}
这也是:
>>> json = dumps(['foo', 'bar', dict(date=date)]) >>> json '["foo", "bar", {"date": "2010-07-15T13:16:38.365579"}]' >>> loads(json) [u'foo', u'bar', {u'date': datetime.datetime(2010, 7, 15, 13, 16, 38, 365579)}]
但这不能按预期工作:
>>> json = dumps(['foo', 'bar', date]) >>> json '["foo", "bar", "2010-07-15T13:16:38.365579"]' >>> loads(json) [u'foo', u'bar', u'2010-07-15T13:16:38.365579']
这是代码:
__all__ = ['dumps', 'loads'] import datetime try: import json except ImportError: import simplejson as json class JSONDateTimeEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, (datetime.date, datetime.datetime)): return obj.isoformat() else: return json.JSONEncoder.default(self, obj) def datetime_decoder(d): if isinstance(d, list): pairs = enumerate(d) elif isinstance(d, dict): pairs = d.items() result = [] for k,v in pairs: if isinstance(v, basestring): try: # The %f format code is only supported in Python >= 2.6. # For Python <= 2.5 strip off microseconds # v = datetime.datetime.strptime(v.rsplit('.', 1)[0], # '%Y-%m-%dT%H:%M:%S') v = datetime.datetime.strptime(v, '%Y-%m-%dT%H:%M:%S.%f') except ValueError: try: v = datetime.datetime.strptime(v, '%Y-%m-%d').date() except ValueError: pass elif isinstance(v, (dict, list)): v = datetime_decoder(v) result.append((k, v)) if isinstance(d, list): return [x[1] for x in result] elif isinstance(d, dict): return dict(result) def dumps(obj): return json.dumps(obj, cls=JSONDateTimeEncoder) def loads(obj): return json.loads(obj, object_hook=datetime_decoder) if __name__ == '__main__': mytimestamp = datetime.datetime.utcnow() mydate = datetime.date.today() data = dict( foo = 42, bar = [mytimestamp, mydate], date = mydate, timestamp = mytimestamp, struct = dict( date2 = mydate, timestamp2 = mytimestamp ) ) print repr(data) jsonstring = dumps(data) print jsonstring print repr(loads(jsonstring))
如果你确定只有Javascript会使用JSON,我更喜欢Date
直接传递Javascript 对象.
对象ctime()
上的方法datetime
将返回Javascript Date对象可以理解的字符串.
import datetime date = datetime.datetime.today() json = '{"mydate":new Date("%s")}' % date.ctime()
Javascript很乐意将它用作对象文字,并且你已经内置了Date对象.
比赛后期...... :)
一个非常简单的解决方案是修补json模块的默认值.例如:
import json import datetime json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)
现在,您可以使用json.dumps(),就像它始终支持datetime一样...
json.dumps({'created':datetime.datetime.now()})
如果您要求json模块的这个扩展始终启动并希望不改变您或其他人使用json序列化的方式(在现有代码中或不在现有代码中),这是有意义的.
请注意,有些人可能会认为以这种方式修补库是不好的做法.如果您希望以多种方式扩展您的应用程序,则需要特别小心 - 在这种情况下,我建议使用拉面或JT的解决方案并在每种情况下选择适当的json扩展.
除了时间戳之外,添加到社区维基的答案并不多!
Javascript使用以下格式:
new Date().toJSON() // "2016-01-08T19:00:00.123Z"
Python方面(对于json.dumps
处理程序,请参阅其他答案):
>>> 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这样的前端框架无法在浏览器本地时区显示日期:
> $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"