mysql中default只允许current_timestamp、localtime、localtimestamp(无参或带精度),now()、current_time、sysdate()等均非法;timestamp自动时区转换且范围窄(1970–2038),datetime不转换、范围宽(1000–9999),跨时区或长期存储应优先选datetime。

TIMESTAMP 字段设 DEFAULT CURRENT_TIMESTAMP 是可行的,但必须注意版本行为、时区影响和隐式约束——不是所有“当前时间”写法都合法,也不是所有场景都该用 TIMESTAMP。
为什么不能用 NOW() 或 SYS_DATE() 作默认值
MySQL 在 DEFAULT 子句中只认三个等价函数:CURRENT_TIMESTAMP、LOCALTIME、LOCALTIMESTAMP(无参数或带精度如 CURRENT_TIMESTAMP(3))。其他时间函数一律报错 ERROR 1064:
-
DEFAULT NOW()→ 不合法,NOW()是运行时函数,不被DEFAULT语法接受 -
DEFAULT CURRENT_TIME→ 错误,它是TIME类型函数,不能用于TIMESTAMP或DATETIME -
DEFAULT SYSDATE()→ 不支持,默认值上下文不执行语句级函数 -
DEFAULT '2026-04-14 15:21:00'→ 合法但静态,不是“当前时间”
TIMESTAMP vs DATETIME:选哪个设默认当前时间
两者都能用 DEFAULT CURRENT_TIMESTAMP,但关键差异直接影响数据一致性:
-
TIMESTAMP自动做时区转换:存入时转为 UTC,查出时转回客户端时区。如果你的业务跨时区且依赖精确时间比对(比如日志分析),可能看到“同一行数据在不同时区查出来时间不同” -
DATETIME原样存储,不转换。适合记录用户本地操作时间(如“用户在北京时间 14:00 提交订单”) -
TIMESTAMP范围窄(1970–2038),DATETIME宽(1000–9999),金融/历史系统务必选后者 - MySQL 5.6.5+ 才支持
DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;旧版本只能用TIMESTAMP
explicit_defaults_for_timestamp = OFF 会悄悄破坏你的默认值
MySQL 5.6.5 之前默认开启隐式行为,5.6.5+ 默认 OFF,但很多 RDS 实例(尤其老配置)仍保留 OFF。此时:
- 定义
TIMESTAMP字段却不显式写DEFAULT,MySQL 会自动加DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP—— 你没写,它帮你加了 - 如果表里已有两个
TIMESTAMP字段,第二个会报错Invalid default value for 'xxx',因为 MySQL 只允许一个隐式默认时间戳 - 解决方案是显式设置参数:
SET GLOBAL explicit_defaults_for_timestamp = ON,然后重建表或用ALTER TABLE ... MODIFY COLUMN显式声明每个TIMESTAMP的默认行为
建表和改表时的正确写法示例
建表时直接定义最安全:
CREATE TABLE logs ( id INT PRIMARY KEY AUTO_INCREMENT, event VARCHAR(100), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );
已有表加默认值,注意语法版本差异:
- MySQL 8.0.13+:用
ALTER TABLE logs ALTER COLUMN created_at SET DEFAULT CURRENT_TIMESTAMP - 旧版本:必须重定义字段,例如
ALTER TABLE logs MODIFY COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - 修改已有字段的默认值,不会影响存量数据;只对后续
INSERT且未指定该列时生效
最易忽略的一点:ON UPDATE CURRENT_TIMESTAMP 对 UPDATE ... SET col = col 这种“值没变”的操作依然触发更新——只要语句里提到了该字段,时间就会刷,哪怕实际值没变。











