当前位置:  开发笔记 > 编程语言 > 正文

Python和JavaScript之间的JSON日期时间

如何解决《Python和JavaScript之间的JSON日期时间》经验,为你挑选了8个好方法。

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



1> JT...:

您可以将'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))

更新:添加了类型和值的输出.
更新:还处理日期


lambda可以适用于在非日期时间类型上调用基本实现,因此如果需要可以引发TypeError:`dthandler = lambda obj:obj.isoformat()if isinstance(obj,datetime)else json.JSONEncoder().default (OBJ)`
问题是如果你在list/dict中有一些其他对象,这段代码会将它们转换为None.
完整输出格式也应该有时区...而isoformat()不提供此功能...所以你应该确保在返回之前在字符串上附加该信息
json.dumps也不知道如何转换它们,但是异常正在被压制.可悲的是,一线lambda修复有它的缺点.如果您希望在未知数上引发异常(这是一个好主意),请使用我上面添加的函数.
这是最好的方式.为什么没有选择这个答案?
lambda one-liner的一个小简化:`if isinstance(obj,(datetime.datetime,datetime.date))`将消除对`或`的需要

2> max..:

对于跨语言项目,我发现包含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`:datetime.isoformat()和`simplejson`本机支持,默认情况下将`datetime`对象转储为`isoformat`字符串.不需要手动`strftime`黑客攻击.
@jrk - 我没有从`datetime`对象自动转换为`isoformat`字符串.对我来说,`simplejson.dumps(datetime.now())`产生`TypeError:datetime.datetime(...)不是JSON可序列化的`
`json.dumps(datetime.datetime.now().isoformat())`是神奇发生的地方.
simplejson的美妙之处在于,如果我有一个复杂的数据结构,它将解析它并将其转换为JSON.如果我必须为每个datetime对象执行json.dumps(datetime.datetime.now().isoformat()),我就失去了它.有没有办法来解决这个问题?

3> user240515..:

我已经解决了.

假设您有一个使用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)



4> 小智..:

使用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"]'


次要增强 - 使用`obj.isoformat()`.你也可以使用更常见的`dumps()`调用,它带有其他有用的args(比如`indent`):simplejson.dumps(myobj,cls = JSONEncoder,...)
因为那会调用JSONEncoder的父方法,而不是DateTimeJSONEncoder的父方法.IE,你会上升两个级别.

5> Chris Arndt..:

这是一个相当完整的解决方案,使用标准库json模块递归编码和解码datetime.datetime和datetime.date对象.这需要Python> = 2.6,因为自那时起,%fdatetime.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))



6> Triptych..:

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

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

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

Javascript很乐意将它用作对象文字,并且你已经内置了Date对象.


`.ctime()`是传递时间信息的一种非常糟糕的方法,`.isoformat()`要好得多.`.ctime()`的作用就是抛弃时区和夏令时,就像它们不存在一样.该功能应该被杀死.
技术上不是有效的JSON,但它是一个有效的JavaScript对象文字.(为了原则,我将Content-Type设置为text/javascript而不是application/json.)如果消费者将***和*永远*只**一个JavaScript实现,那么是的,这是非常优雅的.我会用它.

7> davidhadas..:

比赛后期...... :)

一个非常简单的解决方案是修补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扩展.


这默默地吃掉不可序列化的对象并将它们变成"无".您可能希望抛出异常.

8> user1338062..:

除了时间戳之外,添加到社区维基的答案并不多!

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"

推荐阅读
N个小灰流_701
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有