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 handles only basic JSON data types such as strings, numbers, booleans, lists, and dictionaries. A datetime.datetime object is a Python-specific type, so json.dumps raises TypeError: Object of type datetime is not JSON serializable when it encounters one.
To fix that, convert datetime values into a JSON-friendly representation before encoding them. In practice, the best options are ISO 8601 strings, a custom default function, or a reusable JSONEncoder subclass.
Why The Error Happens
JSON itself has no official datetime type. That means every application must decide how dates and times should be represented. Python's standard library intentionally does not guess for you because one system may want ISO strings while another expects Unix timestamps.
This fails because finished_at is a datetime object:
If you run that code, json.dumps stops at the unsupported value and throws the serialization error.
Convert Datetimes To ISO 8601 Strings
The simplest fix is to call isoformat() when building the payload. ISO 8601 is readable, widely accepted by APIs, and easy to parse later.
This is usually the best option when you know exactly which fields are datetimes. It keeps the conversion explicit and makes the payload format obvious to future readers.
If an external system requires a custom shape, strftime() also works:
Use custom formatting only when a contract requires it. Otherwise, ISO 8601 is the safer default.
Use default= For Centralized Conversion
When datetime values appear throughout an application, converting each field manually becomes repetitive. json.dumps accepts a default callback that can serialize unsupported objects in one place.
This pattern is useful when payloads are nested or shared across modules. It also fails loudly for unknown types instead of silently converting everything with str().
Create A Custom JSON Encoder
If you need the same behavior everywhere, define a custom encoder class and pass it with cls=.
This is a good fit for shared libraries, API clients, or framework code where serialization rules should stay consistent across the project.
Strings Versus Timestamps
Some systems prefer Unix timestamps instead of strings. That is also valid, but it is less self-explanatory and easier to misuse when timezone handling is unclear.
Timestamps are compact and common in analytics pipelines, but ISO strings are usually easier to debug and safer for public APIs.
Common Pitfalls
One common mistake is serializing naive datetimes that have no timezone. The value may look correct, but downstream systems cannot tell whether it represents local time or UTC. Prefer timezone-aware values, often in UTC, before calling isoformat().
Another mistake is using default=str as a quick fix. That avoids the immediate exception, but it converts every unsupported object with whatever str() returns, which can hide bugs and make payloads inconsistent.
It is also easy to forget the decoding side. Once you serialize a datetime, the receiver gets a string or number, not a Python datetime object. If your code later needs datetime arithmetic, parse the value back explicitly.
Summary
- '
datetime.datetimeis not a native JSON type, sojson.dumpscannot encode it automatically.' - '
isoformat()is the simplest and most portable solution for most applications.' - Use
default=or a customJSONEncoderwhen datetime values appear in many payloads. - Prefer timezone-aware datetimes so serialized values are unambiguous.
- Avoid broad shortcuts such as
default=strunless you accept the loss of type control.

