ThinkPHP模型中createTime和updateTime不生效,需显式启用自动时间戳(TP6设$autoWriteTimestamp=true,TP5.1需配合$createTime/$updateTime属性),字段名须与数据库列名完全一致(含大小写、下划线),且避免被allowField过滤;TP6默认仅插入时写入createTime,更新时不覆盖。

ThinkPHP 模型里 createTime 和 updateTime 不生效?先看是否启用了自动时间戳
默认情况下,ThinkPHP 的模型不会自动写入时间戳字段,哪怕你设置了 createTime 和 updateTime 属性。必须显式开启时间戳功能,否则字段名再对也白搭。
- 在模型类中设置
protected $autoWriteTimestamp = true;(TP6.0+)或protected $autoWriteTimestamp = 'datetime';(指定类型) - 若用的是 TP5.1,对应属性是
protected $autoWriteTimestamp = true;,且需配合protected $createTime/protected $updateTime一起使用 - 注意:TP6 默认关闭自动时间戳,TP5.1 默认开启但仅识别
create_time/update_time,自定义字段名必须手动配置
改字段名必须配 createTime 和 updateTime 属性,且不能带下划线前缀
ThinkPHP 对字段名的解析是“原样写入”,不支持自动驼峰转下划线。比如你想用 _createTime 作为数据库字段,模型里就得写成字符串 '_createTime',而不是靠框架帮你转换。
- TP6 示例:
protected $createTime = '_createTime'; protected $updateTime = '_updateTime';
- TP5.1 同理,但要注意:如果数据库字段是
create_time,而你设$createTime = 'createTime',那写入时就会去找不存在的字段,报错或静默失败 - 字段名必须和数据库实际列名完全一致(包括大小写、下划线),TP 不做任何映射或标准化
插入/更新时字段没被写入?检查是否被 allowField 或 field 过滤掉了
时间戳字段属于“非表单数据”,容易被显式字段限制误杀。尤其在用 allowField(true) 或手动传 field 数组时,_createTime 这类字段很容易被漏掉。
- 调用
save()前,确认没有传入['field' => ['id', 'name']]这类限制,否则时间戳字段直接被忽略 - 若用了
allowField(true),确保数据库字段名确实存在于数据表结构中——框架只校验字段是否存在,不校验是否为时间戳 - 调试技巧:在
save()前 dump$model->getData(),看_createTime是否已生成并存在
TP6 中 createTime 在更新时不生效?这是设计行为,不是 bug
TP6 默认只在 insert 时写 createTime,update 时只写 updateTime。如果你发现更新记录后 _createTime 被覆盖,大概率是因为你手动赋了值,或者用了 saveAll + 数据数组混入。
立即学习“PHP免费学习笔记(深入)”;
- 不要在数据数组里传
'_createTime' => ...,否则会绕过自动逻辑,直接写入你给的值 - 如需强制更新时也保留原值,得在模型的
beforeUpdate钩子里手动恢复:public function beforeUpdate($model) { $model->_createTime = $model->origin('_createTime'); } - TP5.1 行为略有不同:它默认 insert/update 都会尝试写
createTime,所以更易踩坑
allowField 的隐式过滤——这三处不盯紧,改了名字也没用。











