关闭Laravel时间戳需四步:模型设$timestamps=false、迁移删除created_at/updated_at字段、验证表结构无这两列、特殊场景用const CREATED_AT=const UPDATED_AT=null;漏任一环仍会报错或写NULL。

直接在模型里写 $timestamps = false 能关掉自动填充,但多数人卡在“关了还报错”或“字段还在被写 NULL”,根本原因是只改了模型,没动数据库和迁移逻辑。
模型设 $timestamps = false 后还报错“Unknown column 'created_at'”
这是最典型的误判:你以为关了时间戳就万事大吉,其实 Eloquent 在 create() 或 save() 时仍会把 created_at 和 updated_at 当作要插入的字段——哪怕值是 NULL,只要表里没有这两列,MySQL 就直接报错。
- 必须确认数据表结构里真没
created_at和updated_at字段:用DESCRIBE your_table;查 - 如果字段还存在,且带
DEFAULT CURRENT_TIMESTAMP或NOT NULL,即使模型关了,MySQL 可能自动填值或报错 - 已有迁移文件里用了
$table->timestamps()?得补一个新迁移,用$table->dropColumn('created_at')和$table->dropColumn('updated_at')显式删掉
字段必须保留(比如 legacy 表),但不想被 Laravel 触碰
删字段不现实,又不想让 Eloquent 读/写它们——这时候不能只靠 $timestamps = false,它会彻底跳过时间戳逻辑,但如果你手动赋值 $model->created_at = 'xxx',再 save(),Eloquent 仍可能覆盖它。
- 正确做法是设
const CREATED_AT = null;和const UPDATED_AT = null; - 这样 Eloquent 完全忽略这两个字段名,既不自动填、也不自动更新,更不会把它们塞进 INSERT/UPDATE SQL
- 你仍可用
DB::table()或原生 SQL 手动操作这些字段,不受影响 - 注意:只设其中一个为
null(如const UPDATED_AT = null;),created_at仍会按默认行为工作
save() 时临时禁用 updated_at,别传数组参数
很多人试过 $model->save(['timestamps' => false]),结果 updated_at 还是变了——因为 save() 方法根本不认这个键,源码里只处理 touch。
- 临时禁用的正解是:先改属性,再保存:
$model->timestamps = false; $model->save(); - Laravel 10.29+ 推荐用
$model->updateQuietly(['title' => 'new']),它跳过事件和时间戳,比手动开关更干净 - 用
DB::table('posts')->update(...)?那本来就不走 Eloquent 生命周期,updated_at当然不变——这不是 bug,是设计 - 想批量更新又保持时间戳?只能手动加字段:
DB::table('posts')->update(['title' => 'new', 'updated_at' => Carbon::now('UTC')]),记得统一时区
真正“关闭”的关键不在模型那一行代码,而在整个链路:模型声明 → 迁移删字段 → 表结构验证 → 特殊场景用 null 常量兜底。漏掉任何一环,都可能让 created_at 悄悄冒出 NULL 或触发数据库默认值。


















