Laravel时间戳不是“改”出来的,而是通过模型层关键属性和方法控制写入行为、字段名、格式与时区;错配任一环节会导致SQL错误或0000-00-00 00:00:00。

直接说结论:Laravel 时间戳不是“改”出来的,而是通过模型层的几个关键属性和方法控制写入行为、字段名、格式与时区——错配任何一个环节,就会出现 SQLSTATE[HY000]: General error 或时间值为 0000-00-00 00:00:00。
禁用时间戳前先确认表结构是否缺失字段
很多报错其实不是代码问题,而是数据库表里压根没有 created_at 和 updated_at 字段。执行 Model::create() 时 Laravel 默认会尝试写入这两个字段,找不到就抛异常。
- 检查迁移文件是否包含
$table->timestamps(),或手动添加了对应字段 - 如果表是 legacy 系统或日志表,确实不需要时间戳,才考虑禁用
- 禁用方式是设置
public $timestamps = false;,不是$timestamps = FALSE(大小写敏感) - 注意:禁用后,
latest()、oldest()这类依赖时间戳的查询方法将失效
自定义字段名必须同时改常量和数据库列
CREATED_AT 和 UPDATED_AT 是模型级常量,只告诉 Eloquent “往哪写”,不负责建表。你改了常量但没改数据库字段,照样报错。
- 在模型中声明
public const CREATED_AT = 'add_time';和public const UPDATED_AT = 'edit_time'; - 确保数据库中真实存在
add_time和edit_time字段,类型为DATETIME或TIMESTAMP - 不要用
protected或private修饰这两个常量——Eloquent 只认public const - 如果只改一个(比如只要
add_time),另一个设为null:public const UPDATED_AT = null;
$dateFormat 控制的是存储格式,不是显示格式
很多人以为设了 $dateFormat = 'Y-m-d' 就能让数据库只存日期,结果发现还是存了完整时间。这是因为 $dateFormat 影响的是 Eloquent 序列化/反序列化行为,不是 SQL 插入值的生成逻辑。
- 默认值是
'Y-m-d H:i:s',对应 MySQL 的DATETIME类型 - 设为
'U'会存时间戳整数(秒级),要求字段类型是INT或BIGINT - 设为
'Y-m-d'要求字段类型是DATE,否则插入时会被截断或报错 - 这个属性也影响
toArray()和 API JSON 输出里的时间字段格式
中间表时间戳要手动开启 withTimestamps()
多对多关系的中间表(如 role_user)默认完全不处理时间戳,哪怕你加了 created_at 字段也没用。
- 迁移里必须显式添加:
$table->timestamps()或$table->datetime('created_at')->nullable(); - 在关联定义里加链式调用:
return $this->belongsToMany(Role::class)->withTimestamps(); -
withTimestamps()不接受参数,不能写成withTimestamps('add_time') - 使用
sync()、attach()、detach()时才会自动写入;直接DB::table()->insert()不触发
最容易被忽略的一点:全局时区(config/app.php 中的 timezone)只影响 PHP 原生时间函数和 Carbon 默认实例,但模型层的 $dateFormat 和数据库字段类型不自动适配时区偏移——比如设了 Asia/Shanghai 却用 UTC 存储,查出来的时间可能差 8 小时。


















