27

EDIT

This question is not a duplicate of How to overcome "datetime.datetime not JSON serializable"? Because, although this is the same problem, it provides a specific context: Django. And so, there are some solutions that apply here and that do not apply on the provided link's question.


ORIGINAL QUESTION

I followed How to overcome "datetime.datetime not JSON serializable"? but this is not helping

I tried this code

>>> import datetime
>>> a =datetime.date(2014, 4, 25)
>>> from bson import json_util
>>> b = json.dumps(a,default = json_util.default)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/lib/python2.7/json/__init__.py", line 250, in dumps
    sort_keys=sort_keys, **kw).encode(obj)
  File "/usr/lib/python2.7/json/encoder.py", line 207, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencode
    return _iterencode(o, 0)
  File "/home/.../python2.7/site-packages/bson/json_util.py", line 256, in default
    raise TypeError("%r is not JSON serializable" % obj)
TypeError: datetime.date(2014, 4, 25) is not JSON serializable

Can somebody help me with a datetime.date serializer and deserializer.

Alvaro Rodriguez Scelza
  • 3,643
  • 2
  • 32
  • 47
Praveen Singh Yadav
  • 1,831
  • 4
  • 20
  • 31
  • 1
    The accepted answer of the question you posted won't help because it only works with mongodb. But other answers would help. – Leonardo.Z Apr 25 '14 at 06:34
  • 1
    Django now has it's own built in Json encoder to handles dates and uuid, see https://docs.djangoproject.com/en/1.10/topics/serialization/#djangojsonencoder – PhoebeB Apr 05 '17 at 09:06

5 Answers5

64

You can also do this:

def date_handler(obj):
    return obj.isoformat() if hasattr(obj, 'isoformat') else obj

print json.dumps(data, default=date_handler)

From here.

Update as per J.F.Sebastian comment

def date_handler(obj):
    if hasattr(obj, 'isoformat'):
        return obj.isoformat()
    else:
        raise TypeError

print json.dumps(data, default=date_handler)
Antony Hatchkins
  • 31,947
  • 10
  • 111
  • 111
AlexandruC
  • 3,527
  • 6
  • 51
  • 80
14

Convert date to equivalent iso format,

In [29]: datetime.datetime.now().isoformat()
Out[29]: '2020-03-06T12:18:54.114600'
Nishant Nawarkhede
  • 8,234
  • 12
  • 59
  • 81
  • 9
    `a = datetime.now().isoformat()` may be more clear, especially when deserializing `a` back into a `datetime` object. Python [docs](https://docs.python.org/2/library/datetime.html) says that `str(d)` is equivalent to `d.isoformat()`. – Lucas Aug 25 '14 at 00:09
  • 2
    @Lucas: `str(d)` is equivalent to `d.isoformat(' ')` (the default delimiter is `'T'` i.e., it is *not* equivalent to `d.isoformat()`) – jfs May 27 '15 at 07:36
  • 1
    @jfs, you are right. I was citing the `time` object docs instead of `datetime`. See https://docs.python.org/2/library/datetime.html#datetime.datetime.__str__ – Lucas Jan 21 '19 at 10:33
10

See the Extending encoder section from the json package docs https://docs.python.org/2/library/json.html

I have used this method and found it quite effective. I think this is what you are looking for.

import json
class DatetimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.strftime('%Y-%m-%dT%H:%M:%SZ')
        elif isinstance(obj, date):
            return obj.strftime('%Y-%m-%d')
        # Let the base class default method raise the TypeError
        return json.JSONEncoder.default(self, obj)

json.dumps(dict,cls=DatetimeEncoder)
Michael Dorner
  • 17,587
  • 13
  • 87
  • 117
Stephen Hartzell
  • 660
  • 1
  • 7
  • 17
7

You can add a date time encoder into the JSON jumps function when handling model querysets, this is customised a bit as I had issues with the base django model state being parsed

import datetime
import decimal
from django.db.models.base import ModelState

class DateTimeEncoder(json.JSONEncoder):
    def default(self, obj):
       if hasattr(obj, 'isoformat'):
           return obj.isoformat()
       elif isinstance(obj, decimal.Decimal):
           return float(obj)
       elif isinstance(obj, ModelState):
           return None
       else:
           return json.JSONEncoder.default(self, obj)

Then use this class with your json dumps

b = json.dumps(a, cls = DateTimeEncoder)
Greg
  • 101
  • 6
2

I've found this to be invaluable, especially after updating Django from 1.7 to 1.9. Most of this is from the blog http://arthurpemberton.com/2015/04/fixing-uuid-is-not-json-serializable Put this in models.py right under the imports. It'll take care of UUIDs for you too.

from uuid import UUID
import datetime
JSONEncoder_olddefault = JSONEncoder.default
def JSONEncoder_newdefault(self, o):
    if isinstance(o, UUID): return str(o)
    if isinstance(o, datetime.datetime): return str(o)
    return JSONEncoder_olddefault(self, o)
JSONEncoder.default = JSONEncoder_newdefault
std''OrgnlDave
  • 3,912
  • 1
  • 25
  • 34