最稳妥的是使用TIMESTAMP类型配合CURRENT_TIMESTAMP()默认值及ON UPDATE CURRENT_TIMESTAMP()自动更新;DATETIME虽5.6.5+支持但行为受限且依赖SQL mode与时区配置。

timestamp 字段用 CURRENT_TIMESTAMP 作为默认值最稳妥
MySQL 中只有 TIMESTAMP 类型原生支持直接用 CURRENT_TIMESTAMP 作默认值,且能配合 ON UPDATE CURRENT_TIMESTAMP 实现自动更新。如果误用 DATETIME 类型,在 MySQL 5.6.5 之前会报错;5.6.5+ 虽支持,但行为有差异:不自动初始化、不自动更新,除非显式加 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP —— 但即便如此,仍受限于 SQL mode(比如 STRICT_TRANS_TABLES)和时区配置。
-
TIMESTAMP存储的是 UTC 时间,读取时按 session 时区转换,适合记录“事件发生时刻” -
DATETIME存储的是字面时间,不随 session 时区变化,适合记录“预定时间”(如会议开始时间) - 建表时优先选
TIMESTAMP,除非明确需要跨时区不变的字面时间
添加字段时设置默认当前时间,语法必须带括号
很多人写 DEFAULT CURRENT_TIMESTAMP 没问题,但漏掉括号或空格导致语法错误,尤其在 ALTER TABLE 场景下。注意:MySQL 要求 CURRENT_TIMESTAMP 后必须跟括号(哪怕空括号),否则解析失败。
- 正确:
ADD COLUMN create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP() - 错误:
ADD COLUMN create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(MySQL 8.0.28+ 已废弃无括号写法) - 若要同时支持插入和更新自动赋值,加上
ON UPDATE CURRENT_TIMESTAMP() - 字段不能为
NULL且未设默认值,否则插入时可能被填充为'0000-00-00 00:00:00'(尤其在 AWS RDS 等严格 SQL mode 下)
AWS RDS 或其他托管 MySQL 出现 0000-00-00 00:00:00 的根本原因
不是语法写错了,而是数据库 server 层的 SQL mode 把非法时间当错误处理,而某些托管服务(如 AWS RDS 默认启用 NO_ZERO_DATE + STRICT_TRANS_TABLES)会拒绝插入零时间,转而抛错或静默截断 —— 表现就是字段变成全零时间戳。
- 检查方式:
SELECT @@sql_mode;,确认是否含NO_ZERO_DATE或STRICT_TRANS_TABLES - 临时绕过(不推荐生产):
SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';(去掉NO_ZERO_DATE) - 真正解决:确保字段定义中显式写了
DEFAULT CURRENT_TIMESTAMP(),且建表时没漏掉NOT NULL - RDS 参数组里可修改
sql_mode,但需重启或参数组生效,不如从 DDL 层修复来得可靠
修改已有字段为自动时间戳,MODIFY COLUMN 比 CHANGE COLUMN 更安全
用 ALTER TABLE ... CHANGE COLUMN 重定义字段时,如果只改默认值不重复声明类型和约束,容易意外丢掉 NOT NULL 或注释;而 MODIFY COLUMN 只改定义,保留原有属性更可控。
- 安全写法:
ALTER TABLE user MODIFY COLUMN create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP() COMMENT '创建时间'; - 如果字段已存在数据且含 NULL 值,加
NOT NULL会失败,需先UPDATE补全或允许 NULL(但违背初衷) - 已有数据的字段加
ON UPDATE CURRENT_TIMESTAMP()不会影响历史记录,只对后续UPDATE生效 - MySQL 5.6.5+ 才支持对
DATETIME使用ON UPDATE CURRENT_TIMESTAMP(),旧版本只能用触发器模拟
实际中最容易被忽略的是:即使语法全对,只要字段定义里漏了 NOT NULL,又没在 INSERT 语句中显式提供值,在严格模式下就会触发零时间填充 —— 这个坑在本地开发常被掩盖,一上 RDS 就暴露。











