TIMESTAMP 存 UTC 时间,查询时按会话时区转换;DATETIME 纯字面存储,不涉及时区转换。前者适合全球统一时刻,后者适合用户主观时间,需额外标注时区。

TIMESTAMP 会自动做时区转换,DATETIME 完全不转——这是最核心、最不能忽略的行为差异。
为什么 TIMESTAMP 查询结果会“变”?
因为 TIMESTAMP 存的是 UTC 时间戳,不是字面值。插入时 MySQL 把你传的本地时间(比如 '2026-06-06 09:30:00')按当前会话 time_zone 转成 UTC 存;查出来时再按当前会话 time_zone 转回本地时间显示。
这意味着:
- 同一行数据,在
SET time_zone = '+08:00'下查是2026-06-06 09:30:00,在SET time_zone = '+00:00'下查就变成2026-06-06 01:30:00 - 如果你没显式设
time_zone,它默认用服务器的system_time_zone,但应用连接池可能覆盖它 -
SELECT @@time_zone和SELECT @@system_time_zone的值经常不一致,得分别确认
DATETIME 为什么“看起来更稳定”?
DATETIME 就是纯字面存储:你 INSERT 什么,磁盘存什么,SELECT 就返回什么,中间不经过任何时区计算。
但这也带来实际问题:
- 如果应用部署在多个时区(比如美国和中国服务同一张表),写入的
DATETIME值含义完全取决于客户端本地时间,没有统一参考基准 - 你无法靠字段本身判断这个时间属于哪个时区——它不带时区信息,也不做转换,等于“裸时间”
- 迁移数据到不同时区的库时,
DATETIME值不会自适应,而TIMESTAMP会(只要你保持time_zone设置一致)
ON UPDATE CURRENT_TIMESTAMP 在两种类型上的表现差异
两者都支持 DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,但语义不同:
- 对
TIMESTAMP:更新时存的是当前会话时区下的“此刻”,立刻转为 UTC 存储 - 对
DATETIME(MySQL 5.6.5+):更新时直接存当前会话时区下的字面时间,不转 UTC,也不关心时区 - 注意:
TIMESTAMP列如果定义了ON UPDATE,且该列值为NULL,MySQL 5.7 之前会静默设为当前时间;5.7+ 默认行为受explicit_defaults_for_timestamp控制,容易踩坑
跨时区场景下怎么选才不容易出错?
关键看你要表达的语义:
- 要记录“某个事件在全球统一时刻发生”(如订单创建时间、日志打点)→ 用
TIMESTAMP,并确保所有客户端连接使用一致的time_zone(比如统一设为'+00:00') - 要记录“用户主观感知的时间”(如会议预约时间、生日)→ 用
DATETIME,并在业务层明确标注时区(比如额外存一个timezone_offset字段或用VARCHAR记'2026-06-06 14:00:00+08:00') - 别混用:一张表里同时有
TIMESTAMP和DATETIME表示同类时间,后期排查时区问题会非常痛苦
真正容易被忽略的点是:时区转换发生在协议层(MySQL client/server 通信时),不是 SQL 解析阶段。哪怕你在应用里把时间格式化成 ISO 8601 字符串再传,只要没显式指定时区,MySQL 仍按会话 time_zone 解释它。











