JSON 里的时间字段该用什么格式
结论:时间戳和字符串各有取舍,但混用一定出事。推荐统一用 ISO 8601 带时区偏移(或 UTC 的 Z 结尾),存储用 UTC,展示在前端按用户时区转换。

结论:时间字段统一用 ISO 8601 带时区偏移,服务端存 UTC 的 Z 结尾格式,前端按用户时区展示;若选 Unix 时间戳,必须全站统一秒或毫秒并把单位写进字段名,纯日期不要塞进表示时刻的字段。
为什么不能只写「2026-10-30 14:30:00」
这串文本没有时区信息。上海的 14:30 和伦敦的 14:30 相差八小时,程序无法判断该按哪个解释。
JavaScript 的 new Date('2026-10-30 14:30:00') 会按运行环境本地时区解析——同一份数据在服务器和浏览器上得到两个不同的时刻,这类 bug 极难复现。
同理,2026-10-30 这种纯日期也不是时刻,它表示「某一天」,用于生日、账期可以,用于订单创建时间就丢了精度。
两种可用格式
A. ISO 8601 字符串(推荐)
{
"createdAt": "2026-10-30T14:30:00+08:00",
"updatedAt": "2026-10-30T06:30:00Z"
}
优点:人可读、可排序(同格式下字典序等于时间序)、精度可到毫秒或微秒、自带时区。
缺点:比时间戳多十几个字节,解析需要 Date 或 dayjs 之类的库。
B. Unix 时间戳(秒或毫秒)
{ "createdAt": 1793519400 }
优点:紧凑、无歧义、跨语言处理简单。
缺点:人不可读,排查问题时要先转换;秒和毫秒极易混用——1793519400 是秒,1793519400000 是毫秒,差三个数量级,前端一不留神就显示成 1970 年。
如果选时间戳,必须全站统一单位,并在字段名上写清楚:createdAtMs 比 createdAt 安全得多。
具体约定
| 项 | 约定 |
|---|---|
| 传输格式 | ISO 8601,带 Z 或 +08:00 |
| 时区 | 统一 UTC(Z 结尾),避免夏令时问题 |
| 精度 | 毫秒足够;需要更高精度时显式写 2026-10-30T06:30:00.123456Z |
| 字段命名 | createdAt、updatedAt、expiresAt,At 后缀表示时刻 |
| 纯日期 | 用 date 类型字段,如 birthday: "1990-01-01",别塞进 At |
| 时长 | 用整数 + 单位(timeoutMs: 3000),不要用字符串 |
前端展示
new Intl.DateTimeFormat('zh-CN', {
dateStyle: 'medium',
timeStyle: 'short',
timeZone: 'Asia/Shanghai',
}).format(new Date('2026-10-30T06:30:00Z'));
显式指定 timeZone 比依赖浏览器默认值可靠——用户改了系统时区,展示会跟着变,这在某些场景是期望行为,在报表类场景则不是。
常见坑
坑一:new Date('2026-10-30') 被当成 UTC 零点。 按 ECMAScript 规范,只有日期没有时间的字符串按 UTC 解析;带时间的按本地时区解析。所以 2026-10-30 在东八区显示成 10 月 30 日 08:00,日期没变但时刻不对;在西半球可能显示成前一天。
坑二:数据库时区与序列化时区不一致。 MySQL 存 datetime 不带时区,应用层按本地时间写入,读出时又按 UTC 解释,一来一回差 8 小时。用 timestamp 或在应用层统一转换。
坑三:夏令时。 用本地时间存未来的时刻,遇到夏令时切换会出现「这个时间不存在」或「出现两次」。存 UTC 就没有这个问题。
常见问题
如何在 ISO 8601 与 Unix 时间戳之间选择?
需要人可读、可排序、自带时区时选 ISO 8601 字符串,代价是比时间戳多十几个字节,解析需要 Date 或 dayjs 之类的库。只追求紧凑、跨语言处理简单时选时间戳,但必须全站统一秒或毫秒,并在字段名上标明单位。两种格式混用会直接制造「同一时刻被解释成两个值」的故障。
是否可以把纯日期和时刻放在同一个字段?
不建议。纯日期 2026-10-30 表示「某一天」,没有时刻也没有时区;表示时刻的字段则需要精确到时、分甚至毫秒。生日、账期用 date 类型字段,创建时间、更新时间用 ISO 8601 的 At 字段,两者分开约定。
相关工具
- JSON 格式化与校验:核对接口返回的时间字段格式是否统一
- JSON API 数据契约设计要点:字段约定的完整清单