产生这个问题的原因需要从两方面分析:
- MySQL的时区
- Java连接数据库所使用的的时区
首先,从MySQL的时区来看
- 查询当前数据库的时区
show variables like '%time_zone%';
查询结果
mysql> show variables like '%time_zone%'; +------------------+--------+ | Variable_name | Value | +------------------+--------+ | system_time_zone | | | time_zone | SYSTEM | +------------------+--------+
数据库的时区分成两种:
- system_time_zone
- mysql服务启动时读取宿主操作系统的时区,当时读取到什么值就是什么值,是当前时刻快照。该值只有在被重新指定或者重启mysql服务时才可能变化
- time_zone
- 所有连接到此MySQL服务的客户端的时区,(不管是什么形式的客户端,是java通过jdbc连接的程序,还是Navicat这种图形化工具,还是命令行,都叫客户端。)这个时区是可以被覆盖的,例如:jdbc连接中的时区设置。
官方文档说明https://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html
关于timezone的几种取值(取值不区分大小写):
- SYSTEM,表示与系统时区相同。
- 使用时区
- 'Europe/Helsinki'
- 'US/Eastern'
- 'MET'
- 'UTC'
- 字符串,表示与UTC时区的偏移量,格式为HH:MM,前缀‘+’或‘-’,例如'+10:00', '-6:00', 或'+05:30'(小时数小于10,前面的0可加可不加)。在某些情况下,MySQL在存储和检索时会预设前置0。MySQL会将'-00:00' 或'-0:00' 转换成 '+00:00'。 版本8.0.19之前,取值范围为:['-12:59','+13:00']。从版本8.0.19开始,范围变成:['-13:59','+14:00']。
场景分析
jdbc连接时serverTimezone设置为UTC,使用navicat连接后显示的时间数据比实际时间慢8小时。
例如:java应用中新建的时间为"2022-05-01 00:00:00",但navicat连接后显示的时间数据为"2022-04-30 16:00:00"。
原因在于:navicat作为客户端连接的时区没有指定,使用默认时区即与系统时区(国内时区)相同。java应用连接配置时区为UTC,UTC时区比系统时区早8小时。同理,若两个java应用的时区不同,获取到的当前时间就需要按照时区进行加减。



