Is it possible to convert datetime into a readable JSON format (which could be used from javascript)? Currently jsonpickle provides only a binary encoded value for datetime.
There are several gotchas here:
First, please don't traffic in timezone unaware datetime objects. You will feel pain, not today, maybe not tomorrow, but someday. You can learn from others' mistakes (mine), or you can learn the hard way. As far as I'm concerned the fact that Python allows you to make datetime objects without a timezone at all is a bug.
Second, you can't reliably roundtrip strftime()
and strptime()
for timezone-aware datetime objects. This was fixed for UTC in Python 3.6, but still fails for other timezones.
Instead use datetime.isoformat()
and datetime.fromisoformat()
. These were added to the datetime
class in Python 3.7 (and backported to earlier versions).
Third, jsonpickle
does not clearly document how to roll your own DatetimeHandler
. So yeah, you just want something legible that you send to Javascript or whatever? The solutions above will be fine. You want something that's legible but you also want to pull it back into Python at some point? Um, trickier.
Here's a hint: when you are subclassing a library to extend its capability, look carefully at the superclass you are extending.
I would have written DatetimeHandler
somewhat differently. But the following works, and contains all my hard won wisdom on the subject. Ouch.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With