jsonpickle datetime в читаемый формат json
Можно ли конвертировать datetime в читаемый формат JSON (который можно использовать из javascript)? В настоящее время jsonpickle предоставляет только двоичное значение для datetime.
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)
Здесь есть несколько ошибок:
Во-первых, пожалуйста, не торгуйте в часовых поясах, не зная объекты даты и времени. Вы будете чувствовать боль не сегодня, может быть, не завтра, а когда-нибудь. Вы можете учиться на чужих ошибках (моих), или вы можете учиться трудным путем. Что касается меня, то, что Python позволяет вам создавать объекты даты и времени без часового пояса, является ошибкой.
Во-вторых, strptime не обрабатывает часовые пояса! Таким образом, вы поступаете правильно, а затем записываете свою дату в каком-то формате и хотите прочитать ее обратно, и kablooey, вы получаете "%z bad formatting string". Grr.
Используйте библиотеку iso8601 для разбора ваших строк даты и времени ISO8601. Часовые пояса обрабатываются.
В-третьих, jsonpickle не содержит четких документов о том, как накатывать свой собственный DatetimeHandler. Так что да, вы просто хотите что-то разборчивое, что вы отправляете в Javascript или что-то еще? Решения выше будет хорошо. Вы хотите что-то разборчивое, но в какой-то момент вы хотите вернуть его обратно в Python? Хм, сложнее.
Вот подсказка: когда вы наследуете библиотеку для расширения ее возможностей, внимательно посмотрите на суперкласс, который вы расширяете.
Я бы написал DatetimeHandler несколько иначе. Но следующие работы, и содержит всю мою трудно завоеванную мудрость по этому вопросу. Уч.
import pytz
import jsonpickle
import iso8601
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 unicode(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 = iso8601.parse_date(args[0])
return value
jsonpickle.handlers.registry.register(datetime, DatePickleISO8601)
С текущей версией jsonpickle (полученной из pip на сегодняшний день), кажется, простое использование кодирования просто работает, если установить unplickable в false:
>>> 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"'