6

是否可以将日期时间转换为可读的 JSON 格式(可以从 javascript 中使用)?目前 jsonpickle 只为日期时间提供二进制编码值。

4

3 回答 3

5

这里有几个陷阱:

首先,请不要在不知道 datetime 对象的时区中进行交通。你会感到疼痛,不是今天,也许不是明天,但总有一天。你可以从别人的错误中学习(我的),或者你可以通过艰难的方式学习。就我而言,Python 允许您在没有时区的情况下创建日期时间对象这一事实是一个错误。

其次,您不能可靠地往返strftime()strptime()识别时区的日期时间对象。这已在 Python 3.6 中针对 UTC 进行了修复,但对于其他时区仍然失败。

而是使用datetime.isoformat()datetime.fromisoformat()。这些被添加到datetimePython 3.7 中的类中(并向后移植到早期版本)。

第三,jsonpickle没有明确的文件如何滚动你自己的DatetimeHandler。所以,是的,你只是想要一些清晰的东西,你发送到 Javascript 或其他什么?上面的解决方案会很好。你想要一些清晰的东西,但你也想在某个时候把它拉回到 Python 中?嗯,比较棘手。

这里有一个提示:当你继承一个库来扩展它的能力时,仔细查看你正在扩展的超类。

我会写得DatetimeHandler有点不同。但下面的作品,包含了我在这个主题上所有来之不易的智慧。哎哟。

import pytz
import jsonpickle
from datetime import datetime

class Blah(object):

    def __init__(self, blah):
        self.datetime = datetime.now(pytz.utc)
        self.blah = blah

    def to_json(self):
        return jsonpickle.encode(self)

    @classmethod
    def from_json(cls, json_str):
        return jsonpickle.decode(json_str)

class DatePickleISO8601(jsonpickle.handlers.DatetimeHandler):
    def flatten(self, obj, data):
        pickler = self.context
        if not pickler.unpicklable:
            return str(obj)
        cls, args = obj.__reduce__()
        flatten = pickler.flatten
        payload = obj.isoformat()
        args = [payload] + [flatten(i, reset=False) for i in args[1:]]
        data['__reduce__'] = (flatten(cls, reset=False), args)
        return data

    def restore(self, data):
        cls, args = data['__reduce__']
        unpickler = self.context
        restore = unpickler.restore
        cls = restore(cls, reset=False)
        value = datetime.fromisoformat(args[0])
        return value

jsonpickle.handlers.registry.register(datetime, DatePickleISO8601)
于 2016-02-25T17:59:13.643 回答
4

使用当前版本的 jsonpickle(从今天的 pip 获得),如果将 unplickable 设置为 false,似乎简单地使用 encode 就可以了:

>>> import jsonpickle
>>> from datetime import datetime
>>> jsonpickle.encode(datetime.now(), unpicklable=False)
'"2014-05-25 20:24:30.357299"'

但是,您的技巧可用于生成ISO 8601 格式,这可能更充分,符合 ECMAScript v5 规范:

>>> class DatetimeHandler(jsonpickle.handlers.BaseHandler):
...     def flatten(self, obj, data):
...             return obj.isoformat()
...
>>> jsonpickle.handlers.registry.register(datetime, DatetimeHandler)
>>> jsonpickle.encode(datetime.now(), unpicklable=False)
'"2014-05-25T20:31:30.422826"'
于 2014-05-25T18:35:11.680 回答
1

经过反复试验,我想出了以下解决方案:

class DatetimeHandler(jsonpickle.handlers.BaseHandler):
    def flatten(self, obj, data):
        return obj.strftime('%Y-%m-%d %H:%M:%S.%f')

jsonpickle.handlers.registry.register(datetime, DatetimeHandler)

encoded_datetime = jsonpickle.encode(datetime.now())
print(encoded_datetime)
decode_datetime = jsonpickle.decode(encoded_datetime)
print(decode_datetime)
于 2013-10-17T08:58:12.663 回答