TP6时间戳需同时启用开关、声明字段名、正确调用:设$autoWriteTimestamp=true,$createTime='create_time',$updateTime='update_time',且仅模型save()等方法触发,Db类直插无效。

ThinkPHP 5.1 升级到 6.0 后模型自动时间戳失效,不是配置“丢了”,而是机制彻底变了——TP6 不再识别 TP5 的 $autoWriteTimestamp(下划线写法),也不默认启用时间戳,更不自动映射字段名。必须三者同时对齐:启用开关、字段名声明、调用方式正确,缺一不可。
核心差异:TP5 和 TP6 时间戳机制完全不同
TP5.1 中只需 protected $autoWriteTimestamp = true;(小驼峰)就能触发,且默认认 create_time/update_time;TP6.x 已废弃该写法,改为显式分离控制:
-
是否启用:靠
protected $autoWriteTimestamp = true;(仅布尔值,不再接受字符串如'datetime') -
创建字段名:必须声明
protected $createTime = 'create_time'; -
更新字段名:必须声明
protected $updateTime = 'update_time'; - 三者缺一,时间戳静默不写入,无报错提示
常见失效原因与对应修复
升级后最常踩的坑集中在以下四点,按优先级排查:
-
模型里还留着 TP5 写法:删掉
protected $_autoWriteTimestamp = true;或protected $autoWriteTimestamp = 'datetime';这类旧配置,只保留纯布尔值的$autoWriteTimestamp = true; -
数据库字段名和模型声明不一致:比如表里是
created_at,但模型中仍写$createTime = 'create_time';必须严格改成$createTime = 'created_at';,大小写、下划线、前缀都要完全匹配 -
字段类型不匹配且没加类型声明:若用
INT存时间戳,需额外加protected $type = ['created_at' => 'integer'];;否则框架尝试写入 Carbon 实例,导致字段为0或空字符串 -
用了
allowField()却漏掉时间字段:例如$model->allowField(['name', 'email'])->save($data),created_at不在白名单里就会被过滤;要么去掉限制,要么显式加入:allowField(['name', 'email', 'created_at'])
必须使用模型 save(),不能用 Db 类直插
自动时间戳只在模型层的主动写入方法中触发,包括:
立即学习“PHP免费学习笔记(深入)”;
-
$model->save()(推荐) $model->data($data)->save()-
Model::create($data)(TP6 中已不推荐,建议统一用save())
以下方式完全不触发时间戳逻辑:
Db::table('user')->insert([...])Db::name('user')->insert([...])- 原生 SQL 或事务中手动拼 INSERT
全局配置可辅助,但不能替代模型设置
虽然可以在 config/database.php 中设 'auto_timestamp' => 'datetime',但 TP6 中该配置仅作为兜底 fallback,不会覆盖模型内明确声明的 $createTime 和 $updateTime。它只在模型未设置 $autoWriteTimestamp = true 时才可能生效,因此建议:
- 关闭全局
auto_timestamp(设为false),避免干扰 - 所有需要时间戳的模型,都显式配置三要素:
$autoWriteTimestamp、$createTime、$updateTime - 字段类型与写入格式保持一致:
'datetime'对应DATETIME字段,'timestamp'对应INT字段(此时模型中还需加$type声明)



















