PHP 的 date_default_timezone_set() 不影响 MySQL 时区,因两者独立;MySQL 需通过配置 default-time-zone = '+08:00' 或连接时执行 SET time_zone 永久/临时同步。
PHP 的 date_default_timezone_set() 不影响 MySQL 时区
很多人以为在 php 脚本开头调用 date_default_timezone_set('asia/shanghai') 就能让 mysql 查询结果里的时间“自动对齐”,其实完全不是一回事。php 时区只管 php 自身的 date()、strtotime() 等函数,mysql 服务端有自己独立的时区设置,两者默认互不干扰。
常见错误现象:NOW() 返回 UTC 时间,但 PHP 显示的是东八区时间;插入带 NOW() 的记录后,查出来的时间比预期早 8 小时;Laravel/Eloquent 中 created_at 存的是 UTC,但页面显示却没转换。
- MySQL 启动时读取系统时区(通常是 UTC),除非显式配置
-
SET time_zone = '+08:00'只对当前连接生效,脚本结束即失效 - PHP 的
mysqli或PDO默认不会自动发SET time_zone命令
phpMyAdmin 提示“时区不匹配”的真实含义
这个提示不是警告你“出错了”,而是告诉你:PHP 报告的时区(date_default_timezone_get())和 MySQL 服务器当前的 time_zone 系统变量值不一致。它只是个对比提醒,不阻断操作,但会影响你对时间字段的直观理解。
验证方式很简单,在 phpMyAdmin 的 SQL 标签页执行:
SELECT @@global.time_zone, @@session.time_zone, NOW(), SYSDATE();
如果前两列返回 SYSTEM 或 +00:00,而 PHP 显示 Asia/Shanghai,提示就必然出现。
立即学习“PHP免费学习笔记(深入)”;
-
@@global.time_zone是 MySQL 服务启动时确定的全局时区(常为SYSTEM,即系统时区) -
@@session.time_zone是当前连接的会话时区,默认继承 global,可被单次修改 - phpMyAdmin 在建立连接后会主动查这两个值,并和 PHP 的时区做字符串比对
让 MySQL 永久使用东八区(推荐方案)
最稳妥的做法是让 MySQL 服务本身运行在 +08:00,避免所有连接层临时设置带来的遗漏风险。这需要修改 MySQL 配置文件,不是改 PHP 或应用代码。
操作路径取决于部署环境:
- Linux(systemd):编辑
/etc/mysql/my.cnf或/etc/my.cnf,在[mysqld]段落下加一行:default-time-zone = '+08:00' - Docker:在
docker run命令中加--env MYSQL_TIME_ZONE='+08:00',或挂载自定义my.cnf - Windows:修改
my.ini,同样加在[mysqld]下
改完必须重启 MySQL 服务,否则不生效。验证是否成功:
SELECT @@global.time_zone;
应返回 +08:00(不是 SYSTEM)。此时 phpMyAdmin 提示会消失,且所有新连接默认使用东八区。
临时同步(仅限无法改 MySQL 配置的场景)
如果你只能动 PHP 层(比如共享主机、云数据库只开放账号权限),就得在每次连接建立后手动设置会话时区。注意:这不是“补救”,而是绕过限制的必要步骤。
对 PDO:
$pdo = new PDO($dsn, $user, $pass, [
PDO::MYSQL_ATTR_INIT_COMMAND => "SET time_zone = '+08:00'"
]);
对 mysqli(面向对象):
$mysqli = new mysqli($host, $user, $pass, $db);
$mysqli->query("SET time_zone = '+08:00'");
- 不能只在 phpMyAdmin 的“SQL”页里手动 SET —— 下次刷新连接就重置了
- 不要在应用里每个查询前都 SET 一次,浪费开销;应该在连接初始化阶段做
- 如果用了连接池或长连接(如 PHP-FPM 持久连接),需确保每次复用连接后仍维持时区,PDO 的
MYSQL_ATTR_INIT_COMMAND是最可靠方式
时区问题真正麻烦的地方不在设置本身,而在于“哪一层该负责什么”。MySQL 存什么、PHP 解释什么、前端渲染什么,三层各自认一时区,就容易串成一锅粥。尤其当数据库迁移、容器重建、或从 UTC 服务器拉取备份时,default-time-zone 这个配置项最容易被忽略。











