ThinkPHP 6+ 默认时区设为 UTC 是为兼容容器部署与跨时区场景,需在 config/app.php 中将 default_timezone 显式设为 'Asia/Shanghai',并确保系统、MySQL 与时区一致。

ThinkPHP 默认时区为什么是 UTC 而不是 PRC
ThinkPHP 6+ 默认把 date_default_timezone_set() 设为 UTC,不是因为疏忽,而是为了兼容容器部署、跨时区 API、数据库统一存储等场景。它假设你通过配置显式覆盖,而不是依赖系统本地时区。一旦漏配,time()、date()、模型自动写入的 create_time 都会比北京时间慢 8 小时。
修改 app.php 中的 default_timezone 配置项
这是最直接有效的办法,但必须改对位置——不是改 config/app.php 里的注释示例,而是改实际生效的键值:
-
default_timezone必须设为'Asia/Shanghai'(不是PRC,PHP 已废弃该缩写) - 不要写成
'+08:00'或'Etc/GMT-8',这些反向命名会导致 +8 小时被解释成 -8 小时 - 确认该配置在应用启动早期就被加载(通常没问题,但若用了自定义引导流程,需检查是否被后续调用覆盖)
数据库时间字段写入仍差 8 小时?检查模型自动时间戳逻辑
即使全局时区设对了,ThinkPHP 的模型时间戳(createTime/updateTime)默认用 time(),而 time() 返回的是 Unix 时间戳(秒数),本身与时区无关;真正出问题的是你用 date('Y-m-d H:i:s') 格式化后存进数据库,或数据库字段类型为 datetime 且 MySQL 服务器时区没同步。
- MySQL 服务端时区应与 PHP 一致:
SELECT @@global.time_zone, @@session.time_zone;,建议设为'SYSTEM'并确保系统时区是Asia/Shanghai - 模型中若手动调用
date('Y-m-d H:i:s'),务必确认此时date_default_timezone_get()返回的是Asia/Shanghai - 更稳妥的做法:模型时间戳字段类型设为
int存 Unix 时间戳,避免任何格式化环节
调试时如何快速验证时区是否生效
别只看页面输出,要分层验证:
立即学习“PHP免费学习笔记(深入)”;
- 在控制器里加一行:
dump(date_default_timezone_get(), date('Y-m-d H:i:s'), time());,确认前两者显示北京时间,time()数值与当前 Unix 时间一致 - 查数据库原始记录,对比
create_time字段值和你执行插入操作时的实际时间 - 注意 CLI 环境(如命令行运行
php think hello)可能读取不同 php.ini,导致时区不一致,需单独检查
真正容易被忽略的是多环境一致性:开发机、测试服、Docker 容器、阿里云 ECS 的系统时区可能各不相同,光改 PHP 配置不够,得让整个链路(系统 → PHP → MySQL → 应用)都对齐 Asia/Shanghai。



















