Skip to content

How to Resolve Python "TypeError: Object of type datetime/Timestamp is not JSON serializable"

Learn how to fix the TypeError when serializing Python datetime or Pandas Timestamp objects to JSON, with methods including .isoformat(), custom default functions, and JSONEncoder subclasses.

When serializing Python objects containing date and time information into JSON format using json.dumps(), you might encounter errors like TypeError: Object of type datetime is not JSON serializable or TypeError: Object of type Timestamp is not JSON serializable. This happens because the standard JSON format doesn't have a native datetime type, and Python's default json encoder doesn't automatically convert Python's datetime.datetime or Pandas' Timestamp objects into a standard JSON representation (like a string).

This guide explains why this error occurs and details several effective methods to serialize these date/time objects into JSON.

Understanding the Error: JSON's Limited Types

JSON has a well-defined set of data types: strings, numbers, booleans (true/false), null, objects ({}), and arrays ([]). It does not have a specific type for dates or timestamps. Therefore, when converting Python objects to JSON, date/time objects must be represented using one of the allowed JSON types, most commonly as strings in a standardized format (like ISO 8601) or sometimes as numbers (like Unix timestamps). Python's default json.dumps() function doesn't automatically perform this conversion for datetime or Timestamp objects.

The Cause: json.dumps() Doesn't Recognize datetime or Timestamp

The TypeError is raised because json.dumps() encounters an object of type datetime.datetime (or pandas.Timestamp) within the data structure you're trying to serialize and doesn't have a built-in rule to convert it to a JSON-compatible type.

import json
from datetime import datetime
import pandas as pd # Requires pandas installation

now_dt = datetime.now()
data_dt = {'event_time': now_dt, 'event_type': 'LOGIN'}
print(f"Data with datetime: {data_dt}")

try:
    json_output_dt = json.dumps(data_dt)
    print(json_output_dt)
except TypeError as e:
    print(f"Error (datetime): {e}")

now_ts = pd.Timestamp.now()
data_ts = {'update_time': now_ts, 'status': 'COMPLETE'}
print(f"Data with timestamp: {data_ts}")

try:
    json_output_ts = json.dumps(data_ts)
    print(json_output_ts)
except TypeError as e:
    print(f"Error (Timestamp): {e}")

The most common and generally recommended approach is to explicitly convert the datetime or Timestamp object into a string before passing the data structure to json.dumps(). This gives you full control over the format.

Using str()

Directly converting using str() produces a default string format, which is usually acceptable but might not be the standard ISO format.

import json
from datetime import datetime

now_dt = datetime.now()
data_dt_str = {'event_time': str(now_dt), 'event_type': 'LOGIN'}

json_output = json.dumps(data_dt_str)
print(f"Serialized (using str()): {json_output}")

Using .isoformat() (Standard Format)

The .isoformat() method returns the date/time in the standard ISO 8601 format (e.g., YYYY-MM-DDTHH:MM:SS.ffffff), which is widely recognized and often preferred for APIs.

import json
from datetime import datetime

now_dt = datetime.now()
data_dt_iso = {'event_time': now_dt.isoformat(), 'event_type': 'LOGIN'}

json_output = json.dumps(data_dt_iso)
print(f"Serialized (using isoformat()): {json_output}")

Using .strftime() (Custom Format)

If you need a specific custom format, use .strftime() with the appropriate format codes.

import json
from datetime import datetime

now_dt = datetime.now()
custom_format = '%Y/%m/%d %I:%M %p' # e.g., YYYY/MM/DD HH:MM AM/PM
data_dt_custom = {'event_time': now_dt.strftime(custom_format), 'event_type': 'LOGIN'}

json_output = json.dumps(data_dt_custom)
print(f"Serialized (using strftime('{custom_format}')): {json_output}")

Solution 2: Use the default Argument in json.dumps()

Instead of converting beforehand, you can tell json.dumps() how to handle types it doesn't recognize using the default argument.

Using default=str

This is a simple way to convert any unrecognized object (including datetime and Timestamp) to its default string representation during serialization.

import json
from datetime import datetime
import pandas as pd

now_dt = datetime.now()
now_ts = pd.Timestamp.now()
data_mixed = {'dt': now_dt, 'ts': now_ts, 'id': 1}

json_output = json.dumps(data_mixed, default=str)

print(f"Serialized (using default=str): {json_output}")

This is concise but applies str() broadly.

Using a Custom default Function (e.g., with isoformat)

Provide a custom function that checks the object's type and returns the desired string format (like ISO format), or raises a TypeError for other unsupported types.

import json
from datetime import date, datetime
import pandas as pd

def datetime_serializer(obj):
    """JSON serializer for datetime/date/Timestamp objects using isoformat."""
    if isinstance(obj, (datetime, date, pd.Timestamp)):
        return obj.isoformat()
    raise TypeError(f"Type {type(obj)} not serializable")

now_dt = datetime.now()
today_d = date.today()
now_ts = pd.Timestamp.now()
data_complex = {'dt': now_dt, 'date': today_d, 'ts': now_ts, 'value': 10}

json_output = json.dumps(data_complex, default=datetime_serializer)

print(f"Serialized (using custom default func): {json_output}")

This offers more control over formatting and handling different types.

Solution 3: Create a Custom JSONEncoder Subclass

For reusable or complex serialization logic across your application, subclass json.JSONEncoder.

import json
from datetime import date, datetime
import pandas as pd

class DateTimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, (datetime, date, pd.Timestamp)):
            return obj.isoformat() # Use ISO format
        return super(DateTimeEncoder, self).default(obj)

now_dt = datetime.now()
data_to_encode = {'timestamp': now_dt, 'status': 'OK'}

json_output = json.dumps(data_to_encode, cls=DateTimeEncoder)

print(f"Serialized (using custom encoder): {json_output}")

This encapsulates the serialization logic within a class.

Handling Pandas Timestamp Objects

All the solutions above work for Pandas Timestamp objects as well:

  • str(my_timestamp)
  • my_timestamp.isoformat()
  • my_timestamp.strftime(...)
  • Using default=str or a custom default function in json.dumps
  • Using a custom JSONEncoder that checks isinstance(obj, pd.Timestamp)

Choosing the Right String Format

  • ISO 8601 (.isoformat()): Highly recommended for interoperability. It's a standard, unambiguous format easily parsed by many languages and systems.
  • str(): Produces a human-readable default format, but less standard for data exchange.
  • strftime(): Use only when you need a specific, non-standard format required by the receiving system.

Conclusion

The TypeError: Object of type datetime/Timestamp is not JSON serializable occurs because standard JSON doesn't have dedicated date/time types, and Python's json.dumps doesn't automatically convert them.

To fix this:

  1. Convert to String First (Recommended for Control): Manually convert the datetime or Timestamp objects to strings using .isoformat() (preferred), str(), or .strftime() before calling json.dumps().
  2. Use default=str or default=custom_func: Let json.dumps() handle the conversion during serialization. Using default=str is simple; a custom function offers more control (e.g., using isoformat).
  3. Use a Custom JSONEncoder: Subclass json.JSONEncoder for reusable or more complex serialization logic.

Representing dates and times as ISO 8601 strings is generally the best practice for JSON serialization.

Navigation