推荐用 datetime,因其不自动时区转换、时间范围更广(1000–9999年)、语义清晰且便于维护;timestamp 虽占4字节且支持自动更新,但存在时区隐式转换、2038年限制等问题。

选 datetime 还是 timestamp,关键看是否需要自动时区转换和自动更新,而不是单纯看“存时间”。多数业务场景下,推荐用 datetime。
时区处理:timestamp 会悄悄转换,datetime 不会
timestamp 在 MySQL 中以 UTC 存储,读写时会根据当前会话的时区设置自动转成本地时间。比如你在北京插入 2024-05-01 10:00:00,数据库存的是对应 UTC 时间(即 2024-05-01 02:00:00),查出来时又转回东八区显示。这容易导致跨时区服务行为不一致,调试困难。
datetime 是“所见即所存”——你插什么,就存什么,不转换。适合记录业务发生的真实本地时间(如订单创建时间、日志打点时间)。
- 如果应用部署在多个时区,且需统一按 UTC 管理时间,可手动用
CONVERT_TZ()或在应用层统一处理,比依赖 timestamp 的隐式转换更可控 - 若真要靠数据库自动做时区适配(比如后台管理按用户时区展示),建议用 datetime + 显式时区字段(如
created_at DATETIME, timezone VARCHAR(10))
时间范围:datetime 更宽,timestamp 有年份限制
timestamp 在 MySQL 中支持范围是 1970-01-01 00:00:01 到 2038-01-19 03:14:07(Unix 时间戳溢出问题)。遇到历史数据(如出生日期、合同起始日)或远期计划(如 2050 年有效期),直接报错。
datetime 支持 1000-01-01 到 9999-12-31,基本覆盖所有业务需求。
- 金融、医疗、档案类系统务必避开 timestamp
- 即使现在不用远期时间,也建议预留扩展性,避免未来迁移成本
自动更新:timestamp 默认带 ON UPDATE CURRENT_TIMESTAMP,datetime 需显式声明
MySQL 中,只有 timestamp 类型能默认启用自动更新行为(如建表时写 updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP)。datetime 从 5.6.5 起也支持,但语法稍长,且老版本不兼容。
但这不是选类型的核心理由——自动更新逻辑更适合由应用层或触发器控制,而非依赖字段类型特性:
- 应用层更新更清晰:每次 UPDATE 都明确 set updated_at = NOW(),语义直观,便于审计
- 避免意外覆盖:timestamp 的 ON UPDATE 在任何 UPDATE 语句中都会触发,哪怕你只改了其他字段
- 若坚持用数据库自动更新,datetime 同样可行,只是写法多几个字
性能与存储:差异极小,别作为决策依据
timestamp 占 4 字节,datetime 占 8 字节;timestamp 索引可能略快(因数据量小),但现代硬件下这点差异几乎不可测。真正影响性能的是索引设计、查询写法和数据量,不是字段类型本身。
为省 4 字节而妥协可维护性和语义清晰度,得不偿失。
- 优先保证业务语义准确:记录“什么时候发生的”,不是“离 Unix 纪元多少秒”
- 团队协作时,datetime 更易理解,减少沟通成本
- ORM 框架(如 Django、Laravel、MyBatis)对 datetime 支持更成熟,timestamp 容易引发时区配置陷阱










