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


当前回答

除了时间戳之外,没有什么要添加到社区wiki答案中!

Javascript使用以下格式:

new Date().toJSON() // "2016-01-08T19:00:00.123Z"

Python端(用于json。转储处理程序,见其他答案):

>>> 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"

其他回答

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

datetime对象上的ctime()方法将返回一个Javascript Date对象可以理解的字符串。

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

Javascript会很乐意使用它作为对象文字,这样就有了内置的Date对象。

对于跨语言项目,我发现包含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字符串,但在互联网上有很多可用的解析器。

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

除了时间戳之外,没有什么要添加到社区wiki答案中!

Javascript使用以下格式:

new Date().toJSON() // "2016-01-08T19:00:00.123Z"

Python端(用于json。转储处理程序,见其他答案):

>>> 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"

我已经算出来了。

假设你有一个Python datetime对象d,是用datetime.now()创建的。其值为:

datetime.datetime(2011, 5, 25, 13, 34, 5, 787000)

你可以将它序列化为JSON格式的ISO 8601 datetime字符串:

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 (JavaScript)日期格式是2012-04-23T18:25:43.511Z - UTC和“Z”。如果不这样做,JavaScript在从字符串创建Date()对象时将使用web浏览器的本地时区。

对于“天真”时间(Python称之为没有时区的时间,这里假设是本地时间),下面将强制使用本地时区,以便它可以正确地转换为UTC:

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)

为什么这么难呢?