timestamp 与 datetime 的选择与时区坑
发布时间:2026-07-20 12:41       
更新时间:2026-07-21 08:11
服务器时区一改,应用里的时间凭空差了八小时——这类问题的源头,常常是 timestamp 类型的特性。把两种类型的存储差异弄清楚,选型和排错都不难。
存储差异
datetime 存字面量:写进去是 2026-10-08 15:00:00,读出来还是它,和时区无关,占 8 字节,表示范围到 9999 年。
timestamp 存的是 UTC(协调世界时)时间戳,占 4 字节,读写时按会话时区换算:写入把会话时区的值转成 UTC 存,读出再转回会话时区显示。会话时区一变,同一条记录读出来的"钟表时间"就变了——时区坑的根源就在这个自动换算上。时间的格式化展示交给应用代码去做,数据库只负责老老实实存和取。
2038 话题
4 字节能表示的上限对应 2038 年 1 月,这就是常说的 2038 问题;新版本已经放宽了这一限制,但大量存量系统仍跑在老版本上,约束依然真实存在。业务会活到 2038 年之后的系统,新表选字段时要把这条算进去,长生命周期的数据优先用 datetime。
统一 UTC 的做法
多时区团队或跨国业务的稳妥做法:存储统一 UTC,展示层按用户所在时区渲染。表设计统一用 datetime 存 UTC 值,应用写入前完成转换(主流语言的标准库都支持),会话时区固定:
SET time_zone = '+00:00';
这样任何一台服务器、任何一个会话读到的都是同一个值,时区问题从根上消失。timestamp 的自动换算留给单时区、简单场景使用,用的时候也要把会话时区在连接串里显式定死,不要依赖服务器默认值。
怎么选
需要跨时区自动换算、追求省事,用 timestamp;业务生命周期长、只存不换算、或应用层已经统一存 UTC 的,用 datetime。更重要的是在团队里定一条规范写进建表模板,别让每张表各自拍板。存量老表不必急着动,新增表按规范来,迁移留给有把握的时候再做。