PyMongo error: Date time ‘…’ is not JSON serializable

Updated: February 12, 2024 By: Guest Contributor Post a comment

Introduction

The PyMongo error, ‘Date time is not JSON serializable’, can occur when attempting to convert MongoDB documents containing DateTime fields to JSON format. MongoDB stores date objects in a format that is not natively recognized by Python’s json library, leading to serialization issues. This tutorial will explore the reasons behind this error and provide comprehensive solutions to resolve it.

Solution 1: Using default=str in json.dumps()

A straightforward solution involves specifying the default parameter in the json.dumps() method to convert non-serializable types to string.

  1. Import the json library.
  2. When calling json.dumps(), use the default=str argument.
  3. Convert your MongoDB documents or DateTime fields using this method.

Example:

import json
from bson import ObjectId
from datetime import datetime

# Assume my_document is a MongoDB document containing an ObjectId and a DateTime field.
my_document = {'_id': ObjectId(), 'created_at': datetime.now()}

# Convert the MongoDB document to a JSON-friendly format.
json_str = json.dumps(my_document, default=str)
print(json_str)

Notes: This method is simple and directly addresses the serialization issue, but converting dates to strings might not be ideal for all applications, particularly if further date manipulation is required post-serialization.

Solution 2: Custom JSON Encoder

For more control over how dates are serialized, you can define a custom JSON encoder by subclassing json.JSONEncoder.

  1. Define a subclass of json.JSONEncoder.
  2. Override the default() method to handle DateTime objects specifically.
  3. Use your custom encoder when calling json.dumps().

Example:

import json
from bson import ObjectId
from datetime import datetime

class CustomJSONEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, datetime):
            return o.isoformat()
        elif isinstance(o, ObjectId):
            return str(o)
        return json.JSONEncoder.default(self, o)

# Example document with ObjectId and DateTime
example_doc = {'_id': ObjectId(), 'created_at': datetime.now()}

# Serialize using the custom encoder
json_str = json.dumps(example_doc, encoder=CustomJSONEncoder)
print(json_str)

Notes: This solution offers flexibility in handling various non-serializable types and can be extended to accommodate other custom types. However, it requires a bit more coding and understanding of JSON serialization processes.

Solution 3: Convert to ISO Format Before Serialization

Manually converting DateTime objects to ISO format before serialization can provide a solution that keeps dates in a standardized and easily manipulable form.

  1. Identify all DateTime fields in your document.
  2. Convert these DateTime fields to ISO format using the datetime.isoformat() method.
  3. Serialize the document normally with json.dumps().

Example:

from datetime import datetime
import json

# Sample document
my_document = {'created_at': datetime.now()}

# Convert DateTime to ISO format
my_document['created_at'] = my_document['created_at'].isoformat()

# Convert to JSON
json_str = json.dumps(my_document)
print(json_str)

Notes: This method retains the date information in a consistent format while also allowing for straightforward serialization. However, it requires manually identifying and converting each date field, which can be cumbersome for documents with numerous date fields or deeply nested structures.