如何设置ThinkPHP模型中的自定义时间戳字段?
- 内容介绍
- 文章标签
- 相关推荐
本文共计727个文字,预计阅读时间需要3分钟。
ThinkPHP默认仅识别`create_time`和`update_time`作为时间戳字段,若数据库表使用的是`created_at`和`updated_at`或其它名称,必须显式配置,否则自动写入将失效。
在模型类中设置两个关键属性即可生效:
-
protected $createTime = 'created_at';—— 指定创建时间字段名 -
protected $updateTime = 'updated_at';—— 指定更新时间字段名(设为false可关闭自动更新) - 两者都需配合
protected $autoWriteTimestamp = true;(TP6 默认开启,但建议显式声明)
为什么设置了字段名,插入时还是没写入时间?
常见原因是字段未被纳入数据写入白名单。ThinkPHP默认对字段做安全过滤,如果 created_at 不在模型的 $schema 或数据库实际字段列表中,会被静默丢弃。
检查并确保以下任一条件满足:
立即学习“PHP免费学习笔记(深入)”;
- 模型已正确关联数据表(
protected $table = 'user';),且该表确实包含created_at字段 - 使用了
protected $schema = ['id', 'name', 'created_at', 'updated_at'];显式声明字段(TP6.1+ 推荐) - 或关闭字段验证:在模型中加
protected $filterField = false;(不推荐,仅用于调试)
手动触发时间戳写入的几种场景
有些操作(如 saveAll()、批量 insert()、原生 SQL)不会走模型的时间戳逻辑,需要手动补全:
- 批量插入前,用
array_map()补时间:['created_at' => date('Y-m-d H:i:s')] - 调用
save()时传入['force' => true]参数可强制写入时间戳字段(即使字段已存在) - 用
data()链式方法预设值:(new User())->data(['name' => 'a'])->save();仍会触发时间戳,但insert()不会
TP5 和 TP6 时间戳行为差异要点
TP5 默认使用 datetime 类型字段 + 字符串格式写入;TP6 默认转为 int 时间戳(秒级),容易导致字段类型不匹配报错。
统一行为建议:
- 若字段是
DATETIME类型,设置protected $dateFormat = 'Y-m-d H:i:s'; - 若字段是
INT类型,保持默认,但注意 MySQL 的timestamp字段范围限制(1970–2038) - TP6 中
$autoWriteTimestamp支持字符串值,如'datetime'或'timestamp',比布尔值更灵活
最常被忽略的是:改了字段名却忘了同步改数据库字段类型和格式配置,结果插入 NULL 或 0 值——务必先查表结构,再配模型。
本文共计727个文字,预计阅读时间需要3分钟。
ThinkPHP默认仅识别`create_time`和`update_time`作为时间戳字段,若数据库表使用的是`created_at`和`updated_at`或其它名称,必须显式配置,否则自动写入将失效。
在模型类中设置两个关键属性即可生效:
-
protected $createTime = 'created_at';—— 指定创建时间字段名 -
protected $updateTime = 'updated_at';—— 指定更新时间字段名(设为false可关闭自动更新) - 两者都需配合
protected $autoWriteTimestamp = true;(TP6 默认开启,但建议显式声明)
为什么设置了字段名,插入时还是没写入时间?
常见原因是字段未被纳入数据写入白名单。ThinkPHP默认对字段做安全过滤,如果 created_at 不在模型的 $schema 或数据库实际字段列表中,会被静默丢弃。
检查并确保以下任一条件满足:
立即学习“PHP免费学习笔记(深入)”;
- 模型已正确关联数据表(
protected $table = 'user';),且该表确实包含created_at字段 - 使用了
protected $schema = ['id', 'name', 'created_at', 'updated_at'];显式声明字段(TP6.1+ 推荐) - 或关闭字段验证:在模型中加
protected $filterField = false;(不推荐,仅用于调试)
手动触发时间戳写入的几种场景
有些操作(如 saveAll()、批量 insert()、原生 SQL)不会走模型的时间戳逻辑,需要手动补全:
- 批量插入前,用
array_map()补时间:['created_at' => date('Y-m-d H:i:s')] - 调用
save()时传入['force' => true]参数可强制写入时间戳字段(即使字段已存在) - 用
data()链式方法预设值:(new User())->data(['name' => 'a'])->save();仍会触发时间戳,但insert()不会
TP5 和 TP6 时间戳行为差异要点
TP5 默认使用 datetime 类型字段 + 字符串格式写入;TP6 默认转为 int 时间戳(秒级),容易导致字段类型不匹配报错。
统一行为建议:
- 若字段是
DATETIME类型,设置protected $dateFormat = 'Y-m-d H:i:s'; - 若字段是
INT类型,保持默认,但注意 MySQL 的timestamp字段范围限制(1970–2038) - TP6 中
$autoWriteTimestamp支持字符串值,如'datetime'或'timestamp',比布尔值更灵活
最常被忽略的是:改了字段名却忘了同步改数据库字段类型和格式配置,结果插入 NULL 或 0 值——务必先查表结构,再配模型。

