datetime和timestamp在存储、时区、范围和性能上差异显著:datetime占8字节、无时区、范围广(1000–9999年)、支持微秒、适合长期存档;timestamp仅4字节、自动时区转换、范围窄(1970–2038年)、支持自动更新,适合跨时区追踪。

MySQL中DATETIME和TIMESTAMP看似相似,实则在存储、时区、范围和性能上差异明显。选错类型不仅浪费空间,还可能引发时区混乱或越界错误。
DATETIME更通用,适合长期存档
DATETIME占用8字节,支持范围从1000-01-01 00:00:00到9999-12-31 23:59:59,不带时区信息,始终按你插入的值原样存储和返回。适合记录创建时间、生效时间等需要长期保留、不依赖本地时区的场景。
- 插入
'2025-04-05 14:30:00',查出来还是'2025-04-05 14:30:00',不受服务器时区影响 - 支持微秒精度(
DATETIME(6)),适合高精度日志或金融时间戳 - 无自动更新行为,需显式指定
DEFAULT CURRENT_TIMESTAMP或ON UPDATE CURRENT_TIMESTAMP
TIMESTAMP更轻量,适合自动追踪
TIMESTAMP仅占4字节,范围窄(1970-01-01 00:00:01 UTC 至 2038-01-19 03:14:07 UTC),但会自动转换:写入时转为UTC存储,查询时再转回当前会话时区。天然适合记录“最后修改时间”这类需跨时区统一管理的字段。
- 服务器设为
Asia/Shanghai,插入'2025-04-05 14:30:00',实际存的是对应UTC时间'2025-04-05 06:30:00' - 同一数据,在纽约客户端查出是
'2025-04-05 02:30:00',在上海查出是'2025-04-05 14:30:00' - 支持
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,一行定义即可自动维护
别踩这些坑
实际开发中常见误用:
- 用TIMESTAMP存出生日期或合同截止日——超出2038年就报错,且语义上无需时区转换
-
多个TIMESTAMP字段都设
DEFAULT CURRENT_TIMESTAMP——MySQL 5.6+只允许第一个有默认值,其余需用NULL或显式赋值 -
升级MySQL 8.0后忽略时区配置——
time_zone设为SYSTEM时,TIMESTAMP行为受系统时钟影响,建议统一设为+00:00或明确时区名 -
迁移数据时忽略精度声明——
TIMESTAMP和DATETIME默认无微秒,若旧表含DATETIME(3),新表未声明会截断毫秒
简单决策树
建表选类型时,按顺序问自己三个问题:
- 这个时间是否需要精确到微秒?→ 是 → 用
DATETIME(6) - 这个时间是否必须在2038年前?且希望跨时区显示一致?→ 是 → 用
TIMESTAMP - 这个时间代表业务事实(如订单下单时间、身份证有效期)?→ 是 → 用
DATETIME










