json.dumps() 默认不支持 datetime、date、time 和 Decimal 类型,需通过 default 参数自定义序列化逻辑;推荐 datetime 转 ISO 格式字符串、Decimal 转字符串以避免精度丢失和时区歧义。

json.dumps() 直接序列化 datetime 会报错
Python 的 json.dumps() 默认不支持 datetime、date、time 或 Decimal 类型,直接传入会抛出 TypeError: Object of type datetime is not JSON serializable。这不是 bug,是设计使然 —— JSON 标准本身没有原生时间或高精度小数类型。
用 default 参数自定义序列化逻辑
最常用也最灵活的方式是通过 default 参数传入一个可调用对象(函数或 lambda),它会在遇到无法序列化的类型时被调用,返回一个 JSON 可接受的替代值(如字符串或数字)。
常见写法示例:
import json from datetime import datetime, date from decimal import Decimaldef json_default(obj): if isinstance(obj, (datetime, date)): return obj.isoformat() # 返回 ISO 8601 字符串,如 "2024-05-20T14:23:11.123456" elif isinstance(obj, Decimal): return float(obj) # 或 str(obj) 保留精度,但前端需配合解析 raise TypeError(f"Object of type {type(obj).name} is not JSON serializable")
data = { "created": datetime.now(), "amount": Decimal("199.99"), "name": "test" } json_str = json.dumps(data, default=json_default)
注意:default 函数必须最终返回 JSON 合法类型(str、int、float、bool、None、list、dict),否则仍会报错。
立即学习“Python免费学习笔记(深入)”;
decimal 处理要小心精度丢失
Decimal 转 float 看似简单,但可能引入浮点误差(例如 Decimal('0.1') → 0.10000000000000000555)。如果业务要求精确表示(如金额),更稳妥的做法是转为字符串:
-
return str(obj):保留全部精度,但前端需主动parseFloat或按字符串处理 -
return obj.to_integral_value() if obj == obj.to_integral_value() else float(obj):整数 Decimal 转 int,小数转 float(仍不完美) - 更严谨方案是统一用字符串 + API 文档约定字段语义,避免隐式类型转换
别忽略 timezone-aware datetime 的序列化差异
带时区的 datetime(如 datetime.now(timezone.utc))调用 isoformat() 会包含 Z 或 +00:00,这是标准且推荐的;但 naive datetime(无时区)的 isoformat() 不含时区信息,容易引发前后端时间误解。
建议在序列化前做显式归一化:
- 统一转为 UTC 并标记时区:
dt.astimezone(timezone.utc) - 或强制转为 naive 并注明“本地时间”,但需上下游严格对齐
- 避免直接序列化 naive datetime,尤其当数据会跨系统流转时
真正麻烦的不是怎么写 default 函数,而是团队是否对时间语义和小数精度有一致理解 —— 这些细节一旦埋下,调试成本远高于写几行序列化代码。










