The ProblemTrying to dump a Python dictionary into a JSON string only to have your program crash is a common rite of passage for developers. You use the standard json.dumps() method, but instead of a clean string, you get a stack trace:
TypeError: Object of type datetime is not JSON serializable
The error usually hits right when you are sending data to an API or saving records to a disk. You'll most likely encounter this wall when fetching rows from PostgreSQL, MySQL, or MongoDB, where timestamp columns are automatically converted into Python datetime objects.
Example Code that Triggers the Error```
import json from datetime import datetime
data = { "id": 1024, "event": "User Signup", "timestamp": datetime.now() # This object causes the crash }
This line raises the TypeError
json_data = json.dumps(data)
## Why This HappensPython's built-in `json` module is efficient but picky. By default, it only understands how to map basic types that have a direct JSON equivalent, such as strings, integers, floats, and booleans. JSON itself has no native 'Date' type. Since the specification doesn't define if a date should be a string or a number, Python refuses to make a guess for you. It simply stops the process.
## How to Fix It### Method 1: The Quick Fix (The 'default' Argument)For small scripts, pass a function to the `default` parameter in `json.dumps()`. This tells the encoder what to do when it hits an object it doesn't recognize.
import json from datetime import datetime
data = {"timestamp": datetime.now()}
Force any non-serializable object into a string
json_data = json.dumps(data, default=str)
print(json_data)
Output: {"timestamp": "2024-06-17 14:30:05.123456"}
While `default=str` is fast, it's a bit of a blunt instrument. You might prefer a more standardized format like ISO 8601.
### Method 2: Custom JSON Encoder (Recommended for Production)If you're building a larger application, a reusable encoder class is the way to go. It keeps your serialization logic in one place and ensures consistency across your entire API.
import json from datetime import datetime, date
class DateTimeEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, (datetime, date)): return obj.isoformat() return super().default(obj)
data = { "created_at": datetime.now(), "is_active": True }
Use the 'cls' argument to use your custom logic
json_data = json.dumps(data, cls=DateTimeEncoder)
print(json_data)
### Method 3: Pre-processing DataSometimes you don't want to change how the encoder works. Instead, you can manually transform the dictionary before passing it to the dump function. This is often safer when you only have one or two date fields.
from datetime import datetime import json
data = {"last_login": datetime.now()}
Create a shallow copy and format the specific field
clean_data = {**data, "last_login": data["last_login"].strftime('%Y-%m-%d %H:%M:%S')}
json_output = json.dumps(clean_data)
### Method 4: Using Pydantic (Modern Python)If you use FastAPI or modern data validation, you likely already have **Pydantic** installed. It handles complex serialization out of the box without any extra configuration.
from pydantic import BaseModel from datetime import datetime
class Event(BaseModel): name: str timestamp: datetime
event = Event(name="System Update", timestamp=datetime.now())
Pydantic v2 uses model_dump_json()
print(event.model_dump_json())
## Verification StepsOnce you've applied a fix, run these checks to ensure your data is actually usable:
- Confirm the script finishes without raising a `TypeError`.- Ensure the output date string looks like `"2024-06-17T10:00:00"` rather than a raw object string.- Verify the JSON is valid by attempting to load it back:```
try:
json.loads(json_data)
print("JSON is valid and ready for use.")
except Exception as e:
print(f"Verification failed: {e}")

