mysql配置文件中default-time-zone必须写在[mysqld]段落下,值为+hh:mm格式(如'+08:00'),写错位置或格式将导致重启后@@global.time_zone仍为system。

my.cnf 里设置 default-time-zone 不起作用?先确认 MySQL 是否支持动态时区
MySQL 5.6.4+ 才真正支持 default-time-zone 配置项,且该值必须是合法时区标识(如 '+08:00' 或 'Asia/Shanghai'),不能填 GMT+8 或 CST——后者会被忽略或解析失败,导致启动报错或静默回退为系统时区。
验证方式:连接 MySQL 后执行 SELECT @@global.time_zone, @@session.time_zone;。若显示 SYSTEM,说明配置未生效;若显示 INVALID,大概率是时区名写错了。
- Linux 系统需确保
mysql_tzinfo_to_sql已导入时区表(mysql.tz_*表存在且非空),否则'Asia/Shanghai'这类命名时区无法识别 - 推荐优先使用偏移量写法(如
'+08:00'),它不依赖时区表,兼容性更强 - 修改
/etc/my.cnf或/etc/mysql/my.cnf的[mysqld]段,添加:default-time-zone = '+08:00'
- 改完必须重启 MySQL(
systemctl restart mysqld),仅重载配置无效
Java 应用仍读到 UTC 时间?检查 JDBC URL 是否覆盖了服务器时区
即使 MySQL 全局时区设对了,JDBC 驱动默认会按服务器时区解析 TIMESTAMP,但若连接字符串中显式指定 serverTimezone,就会以该值为准,覆盖 my.cnf 设置。
常见错误写法:jdbc:mysql://localhost:3306/db?serverTimezone=UTC——这会让 Java 把数据库返回的 TIMESTAMP 当作 UTC 解析,再转成本地时区(比如东八区),结果多减 8 小时。
- 正确做法是让 JDBC 与 MySQL 服务端时区一致:
serverTimezone=GMT%2B8或serverTimezone=Asia/Shanghai - 注意 URL 编码:
+必须写成%2B,否则部分驱动解析失败 - 若用 HikariCP,还需确认
connection-init-sql没有执行SET time_zone = '+00:00'类语句 - Spring Boot 2.3+ 默认启用时区校验,若
serverTimezone和实际不符会抛java.time.DateTimeException
TIMESTAMP 和 DATETIME 行为差异导致时间“看起来”不准
MySQL 的 TIMESTAMP 类型会自动按当前会话时区转换存储和读取,而 DATETIME 是纯字面值、不转换。Java 应用若混用两者,容易误判偏差来源。
例如:插入 2024-01-01 12:00:00 到 TIMESTAMP 字段,在 +08:00 时区下存的是 UTC 时间 2024-01-01 04:00:00;查询时再转回本地时区显示为原值。但如果 JDBC 的 serverTimezone 错配为 UTC,就会把存的 UTC 值直接当本地时间用,造成 8 小时误差。
- 排查时先用
SELECT NOW(), SYSDATE(), UTC_TIMESTAMP();对比三者输出,确认 MySQL 服务端时区逻辑是否符合预期 - Java 中统一用
java.time.LocalDateTime接收DATETIME,用java.time.Instant或ZonedDateTime处理TIMESTAMP - 避免在 SQL 中用
NOW()插入DATETIME字段——它受会话时区影响,不如用SYSDATE()或显式传参
容器化部署时,MySQL 容器时区和宿主机不一致怎么办
Docker 默认继承宿主机时区,但若镜像基础层没装时区数据(如 alpine 镜像),即使 my.cnf 写了 'Asia/Shanghai',MySQL 启动时也会 fallback 到 SYSTEM,最终取容器内 /etc/localtime 的软链目标——而 Alpine 默认没有这个文件。
- Alpine 镜像需在 Dockerfile 中安装 tzdata:
RUN apk add --no-cache tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
- Debian/Ubuntu 镜像可直接挂载宿主机时区:
-v /etc/localtime:/etc/localtime:ro - K8s 中建议通过
env注入TZ=Asia/Shanghai,并确保 MySQL 配置仍用'+08:00'而非依赖系统时区 - 不要依赖
docker run -e TZ=...改变容器时区——MySQL 进程启动后才读取my.cnf,环境变量对其无影响
my.cnf 设 default-time-zone = '+08:00',JDBC URL 写 serverTimezone=GMT%2B8,字段类型优先选 DATETIME 并由应用层控制时区转换。Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











