Python和JavaScript之间的JSON日期时间

Python和JavaScript之间的JSON日期时间,javascript,python,json,Javascript,Python,Json,我想使用JSON从Python发送序列化形式的datetime.datetime对象,并在JavaScript中使用JSON反序列化。最好的方法是什么?如果您确定只有Javascript会使用JSON,我更喜欢直接传递JavascriptDate对象 datetime对象上的ctime()方法将返回Javascript日期对象可以理解的字符串 import datetime date = datetime.datetime.today() json = '{"mydate":new Date("

我想使用JSON从Python发送序列化形式的datetime.datetime对象,并在JavaScript中使用JSON反序列化。最好的方法是什么?

如果您确定只有Javascript会使用JSON,我更喜欢直接传递Javascript
Date
对象

datetime
对象上的
ctime()
方法将返回Javascript日期对象可以理解的字符串

import datetime
date = datetime.datetime.today()
json = '{"mydate":new Date("%s")}' % date.ctime()

Javascript会很高兴地将其用作对象文字,并且您已经将日期对象构建好了。

对于跨语言项目,我发现包含日期的字符串是最好的方法。RfC 3339日期如下所示:

  1985-04-12T23:20:50.52Z
  json.dump(datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ'))
>>> DateTimeJSONEncoder().encode([datetime.datetime.now()])
'["2010-06-15T14:42:28"]'
我认为大多数格式是显而易见的。唯一有点不寻常的事情可能是结尾的“Z”。它代表GMT/UTC。您还可以为CEST(德国夏季)添加一个时区偏移,如+02:00。我个人更喜欢将所有内容保持在UTC格式,直到显示出来

对于显示、比较和存储,您可以在所有语言中将其保留为字符串格式。如果您需要计算日期,可以轻松地将其转换回大多数语言中的本机日期对象

因此,按如下方式生成JSON:

  1985-04-12T23:20:50.52Z
  json.dump(datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ'))
>>> DateTimeJSONEncoder().encode([datetime.datetime.now()])
'["2010-06-15T14:42:28"]'
不幸的是,Javascript的日期构造函数不接受RFC3339字符串,但在Internet上有许多可用字符串


在正确处理时区的同时,尝试处理Python代码中可能遇到的最常见的编码问题,包括date/datetime对象。

您可以将“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"'
这就是格式

更全面的默认处理程序函数:

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))
更新:添加类型和值的输出。

更新:还可以使用
json
处理日期,您可以子类化jsonecoder并覆盖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)
然后,你可以这样称呼它:

  1985-04-12T23:20:50.52Z
  json.dump(datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ'))
>>> DateTimeJSONEncoder().encode([datetime.datetime.now()])
'["2010-06-15T14:42:28"]'

下面是一个使用标准库
json
模块递归编码和解码datetime.datetime和datetime.date对象的完整解决方案。这需要Python>=2.6,因为datetime中的
%f
格式代码。datetime.strTime()格式字符串仅在此后的版本中受支持。对于Python2.5支持,在尝试转换ISO日期字符串之前,请删除
%f
,并从ISO日期字符串中去掉微秒,但您当然会失去微秒精度。为了与其他来源的ISO日期字符串(可能包括时区名称或UTC偏移量)实现互操作性,您可能还需要在转换之前剥离日期字符串的某些部分。有关ISO日期字符串(以及许多其他日期格式)的完整解析器,请参阅第三方模块

只有当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))
\uuuuuuuuuuuuuuuuuuu=['dumps','loads']
导入日期时间
尝试:
导入json
除恐怖外:
将simplejson导入为json
类JSONDateTimeEncoder(json.JSONEncoder):
def默认值(自身、obj):
如果是实例(obj,(datetime.date,datetime.datetime)):
返回对象isoformat()
其他:
返回json.JSONEncoder.default(self,obj)
def datetime_解码器(d):
如果存在(d,列表):
成对=枚举(d)
elif isinstance(d,dict):
pairs=d.items()
结果=[]
对于k,v成对:
如果isinstance(v,基串):
尝试:
#%f格式代码仅在Python>=2.6中受支持。
#对于Python,我已经解决了这个问题

假设您有一个用datetime.now()创建的Python datetime对象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层中接收,就可以构造一个日期对象:

var d = new Date("2011-05-25T13:34:05.787000");
从JavaScript1.8.5开始,日期对象有一个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)
在python方面:

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方面:

var your_date = new Date(data)

如果数据来自python,我的建议是使用库。在pypi.org上可以找到几个

我用这个,效果很好:

游戏后期…:)

一个非常简单的解决方案是修补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序列化的方式(无论是否在现有代码中),这是有意义的

<>请注意,有些人可能会认为修补库是一种错误的做法。
如果您希望以多种方式扩展应用程序,则需要特别小心——如果是这种情况,我建议使用ramen或JT提供的解决方案,并在每种情况下选择适当的json扩展

除了时间戳之外,社区wiki答案中没有太多可添加的内容

Javascript使用以下格式:

new Date().toJSON() // "2016-01-08T19:00:00.123Z"
Python端(对于
json.dumps
处理程序,请参阅其他答案):

如果不使用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"
显然是2012-04-23T18:25:43.511Z-UTC和“Z”。如果没有此JavaScript,则在从字符串创建Date()对象时将使用web浏览器的本地时区

为了“天真”