应将 date_default_timezone_set('asia/shanghai') 仅在 public/index.php 最顶部调用一次,并同步配置 mysql、cli 环境及 config/app.php 中的 default_timezone,确保 php、数据库、命令行等各环节时区统一为东八区。

修改 date_default_timezone_set() 的调用位置
ThinkPHP 启动流程中,date_default_timezone_set() 若被多次调用(比如在 index.php、base.php 或某个中间件里重复设),后一次会覆盖前一次,但框架内部组件(如日志、缓存、模型时间戳)可能已在早期初始化完毕,导致时间显示不一致。
实操建议:
- 全局只在
public/index.php最顶部(require框架入口前)调用一次:date_default_timezone_set('Asia/Shanghai'); - 检查是否在
app/common.php、app/middleware.php或某个BaseController构造函数里又调用了该函数——删掉或注释掉 - 不要在控制器方法里动态改时区,这会影响后续非当前请求的组件行为(比如队列任务里复用的静态时间上下文)
确认 config/app.php 中 default_timezone 配置生效
ThinkPHP 6+ 支持通过配置项 default_timezone 控制部分内置时间行为(如 think\facade\Cache 的过期时间解析),但它**不替代** PHP 原生的 date_default_timezone_set(),也不影响 date()、strtotime() 等函数。
实操建议:
- 确保
config/app.php中存在且值正确:'default_timezone' => 'Asia/Shanghai',
- 该配置仅对框架内少数封装方法起作用(如
Time::now()),不能当作“万能时区开关”依赖 - 如果项目混用原生函数和 ThinkPHP 时间类(比如
date('Y-m-d')和Time::today()),必须保证两者底层时区一致,否则必然出现差 8 小时等现象
数据库时间戳字段与 PHP 时区错位
MySQL 默认使用系统时区,而 PHP 用的是自己设的时区。当模型自动写入 create_time 或 update_time 时,若数据库字段类型是 DATETIME(非 TIMESTAMP),ThinkPHP 写入的是本地时间字符串,而非 UTC;此时若 MySQL 服务器时区是 UTC,就会少 8 小时。
实操建议:
- 查 MySQL 当前时区:
SELECT @@global.time_zone, @@session.time_zone;
,如果不是+08:00或SYSTEM(且系统本身是东八区),需同步调整 - 推荐方案:MySQL 设为
+08:00,PHP 也设为Asia/Shanghai,保持两端物理时间一致 - 避免用
TIMESTAMP字段配合手动时区转换——它会自动转成 UTC 存储再转回,极易在跨时区部署时出问题
命令行执行(如定时任务)时区被忽略
CLI 模式下,PHP 不读取 php.ini 中的 date.timezone(除非显式配置),而 ThinkPHP 的 public/index.php 入口通常只用于 HTTP 请求,命令行脚本(如 think command:run)走的是 think 可执行文件,可能绕过你的时区设置。
实操建议:
- 在
think文件顶部(紧贴#!/usr/bin/env php下一行)加:date_default_timezone_set('Asia/Shanghai'); - 或统一在
config/console.php的启动回调里设(TP6.1+ 支持):'on_start' => function () { date_default_timezone_set('Asia/Shanghai'); } - 验证方式:写个简单命令输出
date('Y-m-d H:i:s'),对比 Web 请求结果是否一致
时区问题从来不是单点配置能兜住的,PHP 层、数据库层、CLI 运行环境、甚至 Docker 容器系统时区,只要有一处没对齐,时间就可能“跳变”。最稳妥的做法是把所有环节都显式锁死到同一时区,而不是指望某一个配置项自动传导。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











