绝大多数业务场景该用timestamp;只有明确需存储2038年后时间或锁定本地字面时刻(如“2050-01-01 09:00北京时间”)才用datetime。

DATETIME 和 TIMESTAMP 不是“随便选一个就行”的类型,选错会导致跨时区时间错乱、2038年数据截断、甚至查不到记录却无报错。
直接结论:绝大多数业务场景该用 TIMESTAMP;只有明确需要存储 2038 年之后的时间,或必须锁定本地字面时刻(比如“会议定在 2050-01-01 09:00 北京时间”),才用 DATETIME。
什么时候用 TIMESTAMP 更安全?
TIMESTAMP 的核心价值是「逻辑时间统一」——它存的是绝对时间点,不是某个时区的挂钟读数。
- 存订单创建时间、日志时间、用户登录时间这类“事件发生时刻”,不管用户在哪、服务器在哪,只要会话时区设对,查出来就是本地可读时间
- 同一条记录,在美国查显示
2026-06-11 15:30:00,在中国查显示2026-06-12 07:30:00,但底层对应的是同一个 UTC 时间点,计算时间差、排序、分组都天然准确 - 占用空间更小(固定 4 字节 vs
DATETIME的 5–8 字节),对千万级表有实际 I/O 和内存收益
容易踩的坑:
-
INSERT INTO t (ts) VALUES (NULL)会自动填当前时间,不是NULL—— 如果业务逻辑依赖显式NULL表示“未设置”,得加NOT NULL DEFAULT '0000-00-00 00:00:00'或改用DATETIME - 插入超范围值(如
'2039-01-01')会静默变成'0000-00-00 00:00:00',且不报错(取决于 SQL mode),查不到数据时很难定位
什么时候必须用 DATETIME?
DATETIME 是“字面时间”,存什么就是什么,不转换、不解释。
- 存历史档案日期(如
'1840-06-01')、长期合约截止日(如'2120-12-31')——TIMESTAMP直接拒绝或截断 - 明确要记录某个本地时刻,且这个时刻不能被时区规则“修正”:比如“公司年会定在北京时间 2050-01-01 19:00”,你希望未来任何人查这条记录,看到的永远是
2050-01-01 19:00,而不是按他所在时区换算后的结果 - 数据迁移或 ETL 场景中,源系统已用字符串或本地时间写死,又不想做时区归一化处理
注意点:
-
DEFAULT CURRENT_TIMESTAMP在DATETIME上不生效(MySQL 5.6.5+ 才支持,且需显式声明) -
ON UPDATE CURRENT_TIMESTAMP对DATETIME也无效,只能靠应用层或触发器维护 - 插入非法日期(如
'2026-02-30')会直接报错Incorrect datetime value,比TIMESTAMP的静默失败更容易暴露问题
别忽略的隐性行为差异
两者看似都返回YYYY-MM-DD HH:MM:SS 格式,但底层机制完全不同:
-
TIMESTAMP的自动转换只发生在字段定义为TIMESTAMP且未显式指定NULL或默认值时;加了DEFAULT CURRENT_TIMESTAMP的列也会触发 - 检查当前会话时区用
SELECT @@time_zone;临时切换测试效果用SET time_zone = '+08:00' -
TIMESTAMP支持毫秒精度(如TIMESTAMP(3)),但范围不变;DATETIME(3)同样支持,且范围更宽 - 索引效率几乎无差别,但单行存储空间差异在高并发写入或大表扫描时会放大
最常被忽略的一点:时区设置不是数据库配置一次就完事的。应用连接池、ORM、客户端会话都可能覆盖全局 time_zone,导致同一张表里部分记录按 UTC 存、部分按 +08:00 存——这种混合使用比单纯选错类型更难排查。











