服务器时间正确,Java程序时区不对问题解决

服务器执行date命令显示时间正确

执行timedatectl status命令结果如下:

看起来是Time zone没有设置好,但是登录另外一台正常的服务器,执行timedatectl status也是一样的

直接写一个简单的Java程序TestTimeZone.java:

Java 复制代码
import java.util.TimeZone;

public class TestTimeZone{
    public static void main(String[] args) {
        System.out.println(TimeZone.getDefault());
    }
}

编译&运行:

javac TestTimeZone.java

java TestTimeZone

分别在两台服务器上运行,对比结果:

//错误时区
sun.util.calendar.ZoneInfo[id="GMT",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]

//正确时区
sun.util.calendar.ZoneInfo[id="Asia/Chungking",offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null]

阅读JDK源码,大致整理了一下Java获取默认时区的流程:

  1. 读取系统属性user.timezone(VM options)
  2. 读取环境变量 TZ 的值
  3. 读取文件/etc/timezone的值
  4. 查找 /etc/localtime文件,如果文件/etc/localtime是软链接,则直接读取软链的路径和文件名作为时区
  5. 如果文件/etc/localtime不是软链接而是一个普通文件,则去/usr/share/zoneinfo目录下读取时区文件,进行内容匹配,匹配到内容一致的文件名作为时区
  6. 如果都找不到,则以GMT作为默认时区

检查两台服务器进行验证,可以确定user.timezone和TZ都是没有设置的,然后/etc/timezone文件也没有,排除掉前3个

查看/etc/localtime文件,不是软链接,是一个普通文件

对 /etc/localtime进行查看:

先查看时区正确的机器,对比/etc/localtime文件和/usr/share/zoneinfo/Asia/Chungking文件,内容是相同的

再查看时区错误的机器,/etc/localtime文件内容和时区正确的机器相同,但是/usr/share/zoneinfo/Asia/Chungking文件内容不知为何被修改了

至此已经定位到原因,实际上即使时区正确的机器,时区设置也不太合理

解决问题的办法很多,可以通过把/etc/localtime软链到时区文件解决

我这里直接采用timedatectl set-timezone Asia/Shanghai命令的方式(实际也是通过软链的方式)

保险起见同时创建/etc/timezone文件,并设置内容为:Asia/Shanghai