Python
JSON Serialization
DateTime object
Programming Troubleshooting
Coding Solutions

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

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Python’s built-in json module can serialize strings, numbers, booleans, lists, and dictionaries, but it does not know what to do with a datetime.datetime object by default. That is why json.dumps raises TypeError unless you convert the value into a JSON-friendly representation first.

Convert datetime to a String

The simplest fix is to convert the value to a string before serialization. ISO 8601 is usually the best choice because it is standard, sortable, and widely understood.

python
1import json
2from datetime import datetime, timezone
3
4payload = {
5    "created_at": datetime.now(timezone.utc).isoformat()
6}
7
8print(json.dumps(payload))

This works because the dictionary now contains only JSON-native types.

The trade-off is that the conversion happens before json.dumps, so every caller must remember to do it consistently.

Use the default Hook in json.dumps

A more reusable pattern is to pass a serializer function through the default parameter.

python
1import json
2from datetime import datetime, timezone
3
4def json_default(value):
5    if isinstance(value, datetime):
6        return value.isoformat()
7    raise TypeError(f"Type not serializable: {type(value)!r}")
8
9payload = {
10    "created_at": datetime.now(timezone.utc)
11}
12
13print(json.dumps(payload, default=json_default))

Now json.dumps delegates unsupported objects to your function. This approach scales better when many payloads include datetimes.

Use a Custom JSON Encoder When You Need Central Control

If your application serializes datetimes in many places, a custom encoder can keep the behavior centralized.

python
1import json
2from datetime import datetime, timezone
3
4class DateTimeEncoder(json.JSONEncoder):
5    def default(self, value):
6        if isinstance(value, datetime):
7            return value.isoformat()
8        return super().default(value)
9
10payload = {"created_at": datetime.now(timezone.utc)}
11print(json.dumps(payload, cls=DateTimeEncoder))

This is useful when you want a consistent house rule for JSON encoding across a codebase.

Avoid the Temptation of default=str

You may see code like this:

python
json.dumps(payload, default=str)

It silences the error, but it is usually too broad. Any unsupported object will be converted with str, which can hide bugs and produce inconsistent formats.

For datetimes, an explicit serializer is better because it states exactly which types are supported and how they should appear in JSON.

Think About Deserialization Too

Serialization is only half the problem. Once a datetime is turned into JSON, it becomes a string. If the receiving side needs a datetime again, it must parse the string explicitly.

python
1from datetime import datetime
2
3text = "2026-03-11T10:30:00+00:00"
4value = datetime.fromisoformat(text)
5print(value)

That is another reason ISO 8601 is a good default: Python can round-trip it cleanly and other systems can usually parse it too.

Prefer Timezone-Aware Values

Naive datetimes serialize, but they can create ambiguity about which timezone the timestamp represents. If the data crosses machine or service boundaries, use timezone-aware values when possible.

python
1from datetime import datetime, timezone
2
3stamp = datetime.now(timezone.utc)
4print(stamp.isoformat())

That avoids the common bug of serializing a local time that later gets interpreted as UTC or vice versa.

Common Pitfalls

  • Passing raw datetime objects to json.dumps and expecting the standard library to guess a format.
  • Converting some datetimes manually and forgetting others in larger payloads.
  • Using default=str and hiding unsupported-type bugs that should be handled explicitly.
  • Ignoring deserialization and then treating the JSON string as though it were still a datetime object.
  • Using naive datetimes where timezone-aware timestamps are required.

Summary

  • 'datetime is not JSON serializable by default in Python’s standard json module.'
  • The usual fix is to convert it to a string, typically with isoformat().
  • The default hook and custom encoders make the conversion reusable.
  • Avoid overly broad fallbacks such as default=str unless that trade-off is intentional.
  • Timezone-aware datetimes produce safer JSON for distributed systems.

Course illustration
Course illustration

All Rights Reserved.