Python json.dumps() 如何处理 datetime/decimal 类型

9次阅读

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

Python json.dumps() 如何处理 datetime/decimal 类型

json.dumps() 直接序列化 datetime 会报错

pythonjson.dumps() 默认不支持 datetimedatetimeDecimal 类型,直接传入会抛出 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 Decimal 

def 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 合法类型(strintfloatboolNonelistdict),否则仍会报错。

立即学习Python免费学习笔记(深入)”;

decimal 处理要小心精度丢失

Decimalfloat 看似简单,但可能引入浮点误差(例如 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 函数,而是团队是否对时间语义和小数精度有一致理解 —— 这些细节一旦埋下,调试成本远高于写几行序列化代码。

text=ZqhQzanResources