Search code examples
pythonjson

How can I overcome "datetime.datetime not JSON serializable"?


I have a basic dict as follows:

sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere

When I try to do jsonify(sample) I get:

TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) is not JSON serializable

What can I do such that my dictionary sample can overcome the error above?

Note: Though it may not be relevant, the dictionaries are generated from the retrieval of records out of mongodb where when I print out str(sample['somedate']), the output is 2012-08-08 21:46:24.862000.


Solution

  • Updated for 2018

    The original answer accommodated the way MongoDB "date" fields were represented as:

    {"$date": 1506816000000}

    If you want a generic Python solution for serializing datetime to json, check out @jjmontes' answer for a quick solution which requires no dependencies.


    As you are using mongoengine (per comments) and pymongo is a dependency, pymongo has built-in utilities to help with json serialization:
    http://api.mongodb.org/python/1.10.1/api/bson/json_util.html

    Example usage (serialization):

    from bson import json_util
    import json
    
    json.dumps(anObject, default=json_util.default)
    

    Example usage (deserialization):

    json.loads(aJsonString, object_hook=json_util.object_hook)
    

    Django

    Django provides a native DjangoJSONEncoder serializer that deals with this kind of properly.

    See https://docs.djangoproject.com/en/dev/topics/serialization/#djangojsonencoder

    from django.core.serializers.json import DjangoJSONEncoder
    
    return json.dumps(
      item,
      sort_keys=True,
      indent=1,
      cls=DjangoJSONEncoder
    )
    

    One difference I've noticed between DjangoJSONEncoder and using a custom default like this:

    import datetime
    import json
    
    def default(o):
        if isinstance(o, (datetime.date, datetime.datetime)):
            return o.isoformat()
    
    return json.dumps(
      item,
      sort_keys=True,
      indent=1,
      default=default
    )
    

    Is that Django strips a bit of the data:

     "last_login": "2018-08-03T10:51:42.990", # DjangoJSONEncoder 
     "last_login": "2018-08-03T10:51:42.990239", # default
    

    So, you may need to be careful about that in some cases.