ThinkPHP模型自动时间戳字段名默认为create_time和update_time,但可通过$createTime、$updateTime属性自定义;save()仅在模型实例调用且未绕过时才触发update_time更新;推荐数据库用DATETIME类型配默认datetime格式,软删除delete_time需手动处理且不联动update_time。

ThinkPHP模型自动时间戳字段名必须是create_time和update_time吗
不是必须,但默认只认这两个字段名。ThinkPHP的auto_write_timestamp机制在开启后,会自动对create_time和update_time写入时间值——哪怕你数据库里实际用的是created_at或mtime,不改配置就完全不会生效。
实操建议:
- 若字段名不同,必须在模型中显式指定:
protected $createTime = 'created_at';和protected $updateTime = 'updated_at'; - 设为
false可关闭对应字段自动写入,比如只希望自动维护创建时间:protected $updateTime = false; - 注意大小写敏感:MySQL列名一般小写,但PHP属性名若写成
$createTime,值必须是字符串(如'created_at'),不能是'CreatedAt'之类
为什么save()没更新update_time,但数据明明改了
常见于手动调用save()时传入了where条件、或用了data() + save()组合,绕过了模型的自动时间戳触发逻辑。
ThinkPHP只在以下情况自动写入update_time:
立即学习“PHP免费学习笔记(深入)”;
- 调用模型实例的
save()(无参数或只传数据数组) - 调用
update()静态方法(且主键存在、能查到原记录) - 使用
allowField(true)等明确放行字段时,update_time仍会被自动追加
容易踩的坑:
-
UserModel::update(['name' => 'a'], ['id' => 1])✅ 自动更新update_time -
(new UserModel())->where('id', 1)->save(['name' => 'a'])❌ 不触发,因为走的是Query类的save,非模型实例方法 - 手动赋值
$user->update_time = time(); $user->save();会覆盖自动逻辑,慎用
时间戳类型选int还是datetime?怎么配置才不丢精度
选datetime更稳妥。ThinkPHP默认用date('Y-m-d H:i:s')格式写入,若数据库字段是int类型,会因类型不匹配导致写入0或报错,且丢失秒级以下精度(比如毫秒场景)。
实操建议:
- 数据库字段用
DATETIME或TIMESTAMP,PHP端保持默认datetime格式 - 若坚持用时间戳整数,需同时改三处:
protected $type = ['create_time' => 'integer']、设置protected $dateFormat = 'U'、确保数据库字段为INT(11) - 注意时区:TP6默认用
date_default_timezone_get(),如果服务器时区是UTC,而业务要东八区时间,得在config/app.php里设'default_timezone' => 'Asia/Shanghai',否则datetime存进去就差8小时
软删除+自动时间戳一起用,deleted_time怎么处理
ThinkPHP的软删除字段delete_time不参与自动时间戳机制,默认不会被自动写入。它只在调用delete()(且启用了软删除)时由框架底层写入,和create_time/update_time是两套逻辑。
所以:
- 不需要、也不应该给
delete_time配$createTime或$updateTime - 若想记录“谁删的”“为什么删”,得手动赋值:
$model->delete_user_id = $uid; $model->delete_reason = $reason; $model->delete(); - 注意:
restore()不会清空delete_time,它只是把该字段设为NULL,所以字段类型必须允许为空
真正容易被忽略的是:软删除状态变更(删/恢复)不会触发update_time更新——哪怕你期望“最后操作时间”包含删除动作,也得自己在事件或重写delete()里补上。



















