在Python开发过程中,使用json模块对数据进行序列化是常见操作,但当数据中包含datetime、date等日期类型的对象时,程序往往会抛出TypeError异常,提示该类型对象不可被JSON序列化。这是因为JSON作为一种轻量级的数据交换格式,其规范仅定义了字符串、数值、布尔值、数组、对象、null这几种基础数据类型,并不支持Python原生的日期时间类型,因此json模块默认无法处理这类对象。

问题复现与原因分析
我们首先通过一个简单的示例来复现这个问题,代码如下:
import json
from datetime import datetime
# 定义包含日期对象的字典
data = {
"name": "测试数据",
"create_time": datetime.now()
}
# 尝试序列化数据
try:
json_str = json.dumps(data)
print(json_str)
except TypeError as e:
print(f"序列化失败:{e}")
运行上述代码后会抛出错误:Object of type datetime is not JSON serializable,这是因为datetime对象不属于JSON规范支持的类型,json模块的默认编码器无法识别并处理它。
解决方案一:自定义JSON编码器
我们可以通过继承json.JSONEncoder类,重写default方法来实现对日期类型的自定义处理,示例代码如下:
import json
from datetime import datetime, date
class CustomJSONEncoder(json.JSONEncoder):
def default(self, obj):
# 处理datetime类型
if isinstance(obj, datetime):
return obj.strftime("%Y-%m-%d %H:%M:%S")
# 处理date类型
if isinstance(obj, date):
return obj.strftime("%Y-%m-%d")
# 其他类型交给父类处理
return super().default(obj)
# 测试自定义编码器
data = {
"name": "测试数据",
"create_time": datetime.now(),
"publish_date": date.today()
}
json_str = json.dumps(data, cls=CustomJSONEncoder, ensure_ascii=False)
print(json_str)
这种方法的好处是可以在全局统一处理所有日期类型的序列化逻辑,不需要每次序列化时单独处理日期字段,适合项目中大量日期对象需要序列化的场景。
解决方案二:序列化前转换日期为字符串
如果不想自定义编码器,也可以在调用json.dumps之前,先将数据中的日期对象转换为字符串格式,代码如下:
import json
from datetime import datetime
def convert_date_to_str(data):
"""递归处理数据中的日期对象,转换为字符串"""
if isinstance(data, dict):
new_data = {}
for key, value in data.items():
new_data[key] = convert_date_to_str(value)
return new_data
elif isinstance(data, list):
return [convert_date_to_str(item) for item in data]
elif isinstance(data, datetime):
return data.strftime("%Y-%m-%d %H:%M:%S")
else:
return data
# 测试转换逻辑
data = {
"name": "测试数据",
"create_time": datetime.now(),
"tags": ["Python", "JSON"]
}
processed_data = convert_date_to_str(data)
json_str = json.dumps(processed_data, ensure_ascii=False)
print(json_str)
这种方式比较灵活,可以针对不同的日期字段定制不同的转换格式,适合只需要处理少量日期对象的场景。
解决方案三:使用第三方库辅助处理
如果不想自己实现转换逻辑,也可以使用第三方库如python-dateutil或者直接使用django等框架内置的序列化工具,以常用的是在json.dumps中传入default参数实现简易转换:
import json
from datetime import datetime
# 使用default参数定义日期转换规则
data = {
"name": "测试数据",
"create_time": datetime.now()
}
json_str = json.dumps(
data,
default=lambda obj: obj.strftime("%Y-%m-%d %H:%M:%S") if isinstance(obj, datetime) else None,
ensure_ascii=False
)
print(json_str)
这种写法比较简洁,适合临时处理少量日期对象的场景,不需要额外定义类或者递归函数。
不同方案对比
下表是三种常见解决方案的适用场景对比:
| 解决方案 | 优点 | 适用场景 |
|---|---|---|
| 自定义JSON编码器 | 全局统一处理,复用性高 | 项目中大量日期对象需要序列化 |
| 预处理转换为字符串 | 灵活度高,可定制转换规则 | 少量日期对象,需要不同转换格式 |
| default参数简易转换 | 代码简洁,无需额外定义 | 临时处理少量日期对象 |
注意事项
- 日期转换为字符串时,建议统一使用ISO 8601格式(如%Y-%m-%d %H:%M:%S),避免不同系统解析时出现格式不兼容的问题。
- 如果序列化后的数据需要反序列化回日期对象,需要在反序列化时手动将字符串转换回日期类型,或者使用支持自动转换的第三方库。
- 自定义编码器时,要注意处理所有可能的日期类型,比如datetime、date、time等,避免出现遗漏导致部分对象无法序列化。
JSON模块日期序列化Python_datetime自定义编码器修改时间:2026-06-21 12:42:28