ThinkPHP 5.1 时间字段存为 INT 时必须显式声明 $type 为 'integer',否则 time() 或 Carbon::now() 被当字符串截断导致秒级精度丢失;paginate() 不触发 getAttr,需手动 array_map 转换;时区不一致或缺少成对的 set/get 时间器也会造成时间显示异常。

ThinkPHP 5.1 时间字段存成 INT 却没配 $type 导致秒级精度丢失
数据库字段是 INT 类型存时间戳,但模型里没声明 protected $type = ['create_time' => 'integer'],框架会把传入的 time() 或 Carbon::now() 当作字符串处理,截断后存进 INT 字段——结果只剩年月日,时分秒全被抹掉。
- 查表结构:
DESCRIBE your_table;确认create_time是INT(10)或INT(11) - 模型必须加类型声明:
protected $type = ['create_time' => 'integer', 'update_time' => 'integer']; - 如果用了
$autoWriteTimestamp = true,还要确保赋值时没手动传'create_time' => time(),否则自动写入被跳过
TP5.1 的 getAttr 不触发于 paginate() 结果,导致格式化失效
你在模型写了 getCreateTimeAttr(),但分页列表里看到的时间还是整数时间戳——因为 paginate() 返回的是原生数组集合,不是完整模型实例,获取器压根不执行。
- TP5.1 中
$type声明对paginate()无效,不能靠它自动转 - 别在模板里用
date('Y-m-d H:i:s', $vo['create_time']),重复又难维护 - 正确做法:查出原始数据后、调用
paginate()前,用array_map()批量转换
$data = Db::name('article')->field('id,title,create_time')->order('id desc')->select();
$data = array_map(function($item) {
$item['create_time'] = date('Y-m-d H:i:s', (int)$item['create_time']);
return $item;
}, $data);
$list = new \think\Paginator($data, 15, input('page/d', 1));
数据库时区 + PHP 时区不一致,让“刚写入的时间”显示错 8 小时
你存了 time()(UTC 秒数),但 MySQL 默认时区是 +00:00,而 PHP 设置了 Asia/Shanghai,读出来再用 date() 格式化时,就自动加了 8 小时——看起来像“未来时间”或“秒被吞掉”。
- 确认 PHP 时区:
date_default_timezone_get()输出是否为Asia/Shanghai - 检查 MySQL 当前时区:
SELECT @@global.time_zone, @@session.time_zone; - 连接后立刻执行:
Db::execute("SET time_zone = '+8:00'");(放在初始化或中间件中) - 更稳妥:统一用
DATETIME字段存时间,避免时间戳跨时区解释歧义
模型里写了 setCreateTimeAttr 却没配 getCreateTimeAttr,读出来变空或报错
修改器 setCreateTimeAttr() 把字符串转成时间戳存进数据库,但没写对应获取器,读出来仍是原始字符串;若字符串格式非法(如 '2024-05-20'),strtotime() 返回 false,再强转 int 就成 0——最终显示为 1970-01-01 08:00:00,看起来像“秒没了”。
立即学习“PHP免费学习笔记(深入)”;
- 修改器和获取器必须成对出现,且逻辑对称
- 获取器开头加空值判断:
if (empty($value)) return '';,避免date()警告 - 不要在获取器里直接
return date('Y-m-d H:i:s', $value),这会丢失原始值;优先返回Carbon::createFromTimestamp($value)(需引入 Carbon)



















