thinkphp 的 default_timezone 配置不控制 php 原生时间函数,仅影响框架内少数封装;其设置易被环境覆盖,且数据库时区需单独配置,docker 中须在 php.ini 层面固化时区。

ThinkPHP 的 default_timezone 配置本身就不控制 PHP 原生时间函数,它只影响框架内少数封装(比如 think\facade\Date),所以“不生效”不是 Bug,而是设计如此。
为什么 config/app.php 里的 default_timezone 看似没用
这个配置项在 ThinkPHP 启动时会被读取,但框架会立即用它调用一次 date_default_timezone_set();问题在于:很多环境(尤其是 Docker 或某些 SAPI)里,PHP 已经通过 php.ini 或系统层设了默认时区(如 UTC),而 ThinkPHP 这次调用又可能被后续代码、扩展或框架自身其他初始化逻辑覆盖。更关键的是:date()、strtotime()、模型自动写入的 create_time 字段,全部依赖 PHP 运行时的全局时区,而不是框架配置。
- 运行
php -r "echo date_default_timezone_get();",如果输出不是Asia/Shanghai,说明框架那行设置根本没落稳 - ThinkPHP 6+ 默认会在启动早期强制设为
UTC,你配的default_timezone只是“建议值”,不是强制锁死 - 如果你在中间件、模型或命令行脚本里又调了一次
date_default_timezone_set(),就可能把前面的覆盖掉
数据库时间仍差 8 小时的根本原因
PHP 显示时间正确 ≠ MySQL 存的时间正确。即使 date('Y-m-d H:i:s') 输出北京时间,只要 MySQL 的 @@session.time_zone 是 UTC 或 +00:00,它就会把传进来的字符串(比如 "2026-09-01 14:15:00")按自己的时区解释——结果就是存成 UTC 时间,查出来自然“慢 8 小时”。
- 执行
SELECT @@global.time_zone, @@session.time_zone;,确认返回值是+08:00或Asia/Shanghai,不是SYSTEM(很多 Docker MySQL 的 SYSTEM 实际指向 UTC) - ThinkPHP 的数据库连接配置里没有自动 SET time_zone,得手动加:
'params' => ['init_commands' => ['SET time_zone = "+08:00"']] - 别指望
default_timezone能让模型字段自动转时区——TP 不做存储 UTC + 读取本地化这层转换,必须自己重写setAttr/getAttr
Docker 环境下 php.ini 修改必须早于容器启动
在容器里只改 ThinkPHP 配置或入口文件加 date_default_timezone_set() 是靠不住的:PHP-FPM 进程一启动,就有请求进来,而你的代码还没执行到那行。真正生效的方案,是在构建镜像阶段就把时区钉死。
- 在
Dockerfile中加:RUN echo "date.timezone = \"Asia/Shanghai\"" > /usr/local/etc/php/conf.d/timezone.ini - 不要用
ENV TZ=Asia/Shanghai+ln -sf /usr/share/zoneinfo/$TZ /etc/localtime这种系统级操作——PHP 不读/etc/localtime,只认date.timezoneini 配置 - 验证是否生效:进容器执行
php -r "echo date('Y-m-d H:i:s e');",输出必须带+08:00,不能是+00:00
真正容易被忽略的是 CLI 和 Web 两套环境的分离:Web 请求走 FPM,读的是 /usr/local/etc/php/php.ini;而定时任务(php think schedule:run)走 CLI,读的是另一份 php --ini 显示的配置。两者时区不一致,就会出现“网页时间对、日志时间错、定时任务时间又不对”的三重混乱。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











