杰瑞科技汇

Python JSON如何处理datetime对象?

Of course! Handling datetime objects with JSON in Python is a very common task. The core issue is that JSON doesn't have a native date/time type. It only supports string, number, boolean, null, array, and object.

Python JSON如何处理datetime对象?-图1
(图片来源网络,侵删)

Therefore, you must convert Python's datetime objects into one of these JSON-compatible types (most commonly a string) before serialization, and then convert them back after deserialization.

Here’s a complete guide covering the best methods, from simple to advanced.


The Problem: TypeError on Serialization

If you try to serialize a datetime object directly, you'll get a TypeError.

import json
from datetime import datetime
data = {
    "user": "Alice",
    "timestamp": datetime.now()
}
# This will raise a TypeError!
# json.dumps(data)
# TypeError: Object of type datetime is not JSON serializable

Solution 1: The Simple default Argument (Good for Quick Scripts)

The json.dumps() function has a default argument. If a value isn't JSON serializable, it calls the function you provide in default and uses its return value.

Python JSON如何处理datetime对象?-图2
(图片来源网络,侵删)

You can pass a simple lambda function that converts the object to its ISO 8601 string representation, which is a standard and unambiguous format.

import json
from datetime import datetime
data = {
    "user": "Alice",
    "timestamp": datetime.now(),
    "login_time": datetime(2025, 10, 26, 10, 30, 0)
}
# Use the default argument with a lambda
json_string = json.dumps(data, default=str)
print(json_string)
# Example Output:
# {"user": "Alice", "timestamp": "2025-10-27T15:45:12.123456", "login_time": "2025-10-26T10:30:00"}
# To deserialize, you need to parse the string back into a datetime object
# This requires a custom hook for json.loads()
def datetime_decoder(dct):
    for key, value in dct.items():
        if isinstance(value, str):
            try:
                # Try to parse as ISO format
                dct[key] = datetime.fromisoformat(value)
            except (ValueError, TypeError):
                # If it's not a datetime string, leave it as is
                pass
    return dct
# Deserializing the JSON string back to a Python dictionary
parsed_data = json.loads(json_string, object_hook=datetime_decoder)
print(parsed_data)
# Output:
# {'user': 'Alice', 'timestamp': datetime.datetime(2025, 10, 27, 15, 45, 12, 123456), 'login_time': datetime.datetime(2025, 10, 26, 10, 30)}

Pros:

  • Simple, no extra libraries needed.
  • datetime.fromisoformat() is built-in and efficient for parsing.

Cons:

  • You have to write and maintain the datetime_decoder function yourself.
  • It will try to parse every string in your JSON, which is inefficient if you have many non-datetime strings.

Solution 2: Using orjson (Highly Recommended for Performance)

The orjson library is a fast, correct JSON library for Python. It's often 2-3x faster than the standard json library and has built-in support for datetime and other common types.

Python JSON如何处理datetime对象?-图3
(图片来源网络,侵删)

First, install it:

pip install orjson

Usage:

orjson automatically serializes datetime objects to ISO 8601 strings and deserializes them back into datetime objects without any extra code.

import orjson
from datetime import datetime
data = {
    "user": "Bob",
    "timestamp": datetime.now(),
    "last_active": datetime(2025, 1, 1, 0, 0, 0)
}
# --- Serialization ---
# orjson.dumps() returns bytes, not a string.
# You need to decode it to get a JSON string.
json_bytes = orjson.dumps(data)
json_string = json_bytes.decode('utf-8')
print(json_string)
# Output:
# {"user": "Bob", "timestamp": "2025-10-27T15:50:00.123456", "last_active": "2025-01-01T00:00:00"}
# --- Deserialization ---
# orjson.loads() takes bytes, so you need to encode the string first.
parsed_data = orjson.loads(json_string.encode('utf-8'))
print(parsed_data)
# Output:
# {'user': 'Bob', 'timestamp': datetime.datetime(2025, 10, 27, 15, 50, 0, 123456), 'last_active': datetime.datetime(2025, 1, 1, 0, 0)}

Pros:

  • Extremely fast.
  • Handles datetime (and date, time, timedelta) automatically.
  • Produces compact, valid JSON.

Cons:

  • Requires an external library (pip install orjson).
  • Returns bytes instead of a str, which is a slight change in API.

Solution 3: The json Module with Custom Encoders/Decoders (The Robust Way)

For full control within the standard library, you can create a custom JSONEncoder and a corresponding object hook for decoding. This is the most robust and maintainable approach for larger applications.

Create a Custom JSONEncoder

Subclass json.JSONEncoder and override its default() method.

from datetime import datetime, date
import json
class DateTimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, (datetime, date)):
            # Convert datetime and date objects to ISO format strings
            return obj.isoformat()
        # Let the base class default method raise the TypeError for other types
        return super().default(obj)

Create a Custom Decoder Hook

This function will be passed to json.loads()'s object_hook. It inspects each dictionary as it's being decoded and attempts to convert string values that look like ISO-formatted dates.

import re
def datetime_decoder(dct):
    # Regex to match ISO 8601 date and datetime strings
    # e.g., "2025-10-27", "2025-10-27T15:50:00", "2025-10-27T15:50:00.123456"
    iso_datetime_pattern = re.compile(r'^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?)?$')
    for key, value in dct.items():
        if isinstance(value, str) and iso_datetime_pattern.match(value):
            if 'T' in value:
                # It's a datetime string
                try:
                    dct[key] = datetime.fromisoformat(value)
                except ValueError:
                    pass # Not a valid datetime, leave as string
            else:
                # It's a date string
                try:
                    dct[key] = date.fromisoformat(value)
                except ValueError:
                    pass # Not a valid date, leave as string
    return dct

Putting It All Together

from datetime import datetime, date
# --- Data to serialize ---
data = {
    "event": "Product Launch",
    "start_date": date(2025, 12, 25),
    "event_time": datetime(2025, 12, 25, 12, 0, 0),
    "details": "A Christmas special."
}
# --- Serialization ---
json_string = json.dumps(data, cls=DateTimeEncoder, indent=2)
print("--- Serialized JSON ---")
print(json_string)
print("\n")
# --- Deserialization ---
parsed_data = json.loads(json_string, object_hook=datetime_decoder)
print("--- Deserialized Python Object ---")
print(parsed_data)
print(f"Type of 'start_date': {type(parsed_data['start_date'])}")
print(f"Type of 'event_time': {type(parsed_data['event_time'])}")

Output:

--- Serialized JSON ---
{
  "event": "Product Launch",
  "start_date": "2025-12-25",
  "event_time": "2025-12-25T12:00:00",
  "details": "A Christmas special."
}
--- Deserialized Python Object ---
{'event': 'Product Launch', 'start_date': datetime.date(2025, 12, 25), 'event_time': datetime.datetime(2025, 12, 25, 12, 0), 'details': 'A Christmas special.'}
Type of 'start_date': <class 'datetime.date'>
Type of 'event_time': <class 'datetime.datetime'>

Pros:

  • Uses only the standard library.
  • Very explicit and robust.
  • Easily extensible to handle other custom types (e.g., UUIDs, Decimals).

Cons:

  • More code to write and maintain compared to the other solutions.

Summary: Which Method Should You Use?

| Method | Best For | Pros | Cons | | :---

分享:
扫描分享到社交APP
上一篇
下一篇