推荐create_time字段用int unsigned或bigint存时间戳,因thinkphp的wheretime()等方法依赖时间戳比较,datetime类型易致查询失效、时区错误及2038问题;模型需同时配置$type为integer和$createtime字段名,模板显示时间需统一php时区为asia/shanghai。

create_time 字段推荐存时间戳(int),不是字符串。ThinkPHP 默认对 datetime 或 date 类型字段不做自动转换,但对整型时间戳字段(如 create_time、update_time)启用了自动写入和自动时间戳功能——前提是模型里正确配置了。
为什么用 int 存时间戳,而不是 varchar 或 datetime
存字符串(如 '2026-04-17 20:55:00')或 MySQL 的 DATETIME 类型看似直观,但在 ThinkPHP 中容易引发三类问题:
- 查询时无法直接用
whereTime()或whereBetweenTime(),因为这些方法底层依赖时间戳比较; - 跨时区场景下,
DATETIME是“本地时间快照”,不带时区信息,strtotime()解析可能出错; - MySQL 的
DATETIME范围是 1000–9999 年,而INT存时间戳(秒级)能覆盖到 2038 年后(需用UNSIGNED INT或BIGINT避免 2038 问题)。
所以:数据库字段类型用 INT UNSIGNED(推荐)或 BIGINT,PHP 层统一用 time() 写入,读取后按需格式化。
模型中开启自动时间戳的两个必要条件
仅声明 protected $autoWriteTimestamp = true; 不够,必须同时满足:
-
protected $type = ['create_time' => 'integer', 'update_time' => 'integer'];—— 显式声明字段类型为整型,否则 ORM 可能当作字符串处理; -
protected $createTime = 'create_time';和protected $updateTime = 'update_time';—— 指定字段名,且字段名必须与数据库一致; - 如果使用软删除,
delete_time同理要加进$type并设为integer。
漏掉 $type 声明,create_time 会被当成字符串传入 SQL,导致写入 0 或报错。
查询时 whereTime() 为什么有时不生效
whereTime('create_time', '>=', 'today') 这类写法依赖 ThinkPHP 内部对字符串日期的解析逻辑,它会调用 strtotime() 转成时间戳再比较。但以下情况会导致失效:
- 数据库字段是
DATETIME类型,而模型没配$type→ 查询条件被当字符串拼接,变成WHERE create_time >= '1713387300',MySQL 类型隐式转换失败; - 服务器时区 ≠ 应用预期时区(如服务器设 UTC,但业务按东八区算 “today”)→
strtotime('today')返回的是 UTC 今日零点,比北京时间早 8 小时; - 想查 “最近 7 天”,误写
whereTime('create_time', 'between', ['7 days ago', 'now']),但 ThinkPHP 不支持这种自然语言,得手动算:time() - 7 * 86400。
稳妥做法:所有时间范围查询都用时间戳数值,例如 where('create_time', '>=', time() - 3600)。
模板里显示时间总少 8 小时?
这是最常被忽略的一点:ThinkPHP 的 date 模板函数(如 {$vo.create_time|date="Y-m-d H:i:s"})完全依赖 PHP 运行时的默认时区,不是数据库或模型配置决定的。
- 检查
php.ini中date.timezone是否设为Asia/Shanghai; - 若不能改 php.ini,在入口文件或公共配置里加
date_default_timezone_set('Asia/Shanghai');; - 不要依赖
datetime($time)辅助函数——它内部也走date(),同样受时区影响。
哪怕数据库存的是正确时间戳,只要 PHP 时区不对,date() 输出就偏移。这个坑不在 ThinkPHP 框架层,而在 PHP 环境本身。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











