【问题标题】:jsonpickle datetime to readable json formatjsonpickle 日期时间到可读的 json 格式
【发布时间】:2013-10-16 21:57:43
【问题描述】:

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

【问题讨论】:

    标签: python python-2.7 python-3.x jsonpickle


    【解决方案1】:

    这里有几个陷阱:

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

    其次,您不能可靠地往返 strftime()strptime() 以获取时区感知日期时间对象。对于 Python 3.6 中的 UTC,这是 fixed,但对于其他时区仍然失败。

    改为使用datetime.isoformat()datetime.fromisoformat()。这些已添加到 Python 3.7 中的 datetime 类(以及早期版本中的 backported)。

    第三,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)
    

    【讨论】:

    • 绝对!请做。
    • 这个答案优于公认的答案,因为它是可逆的。 jsonpickle 的全部意义在于,顾名思义,它是 pickle 的类似物,因此可逆性是隐含的且重要的。
    • 扩展问题。我从jsonpickle 呈现为"date": {"py/object": "datetime.date", "__reduce__": [{"py/type": "datetime.date"}, ["B+ULEA=="]]} 的API 接收数据。这个页面上唯一对我有用的建议是unpicklable=False,但它会导致返回的数据非常庞大——100Mb 或更多。其他都没有任何影响。有什么建议吗?
    【解决方案2】:

    使用当前版本的 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 format,这可能更充分,符合 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"'
    

    【讨论】:

      【解决方案3】:

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

      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)
      

      【讨论】:

      • 生成的 decode_datetime 是 unicode 类型,而不是原始日期时间。第一个答案更适合标记为已接受。
      猜你喜欢
      • 2019-08-17
      • 2022-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-29
      • 1970-01-01
      • 2017-04-03
      • 2022-12-01
      相关资源
      最近更新 更多