JVM 的 TimeZone 被别人改了

昨天有同事让我看看为啥一台QA的机器上的时区变了, 同样的代码在生产环境显示的日期都是 MST 时区(如:Tue Dec 06 06:52:22 MST 2022), 可是QA 环境显示的时间都是 UTC 时区(如: (如:Tue Dec 06 013:52:22 UTC 2022)).

检查步骤:

首先确认这个 Linux 机器上的时区

$ date
Tue Dec 06 013:52:22 UTC 2022

通过以上代码确认, 这个Linux 机器时区是正确的

检查 JVM 的时区

  1. JVM 可以通过启动参数添加: -Duser.timezone="XXXX/YYYY"

    java -Duser.timezone="Asia/Kolkata" com.tianxiaohui.AppMain
  2. 又或者设置系统环境变量添加

    System.setProperty("user.timezone", "Asia/Kolkata");
  3. 又或者通过设置默认时区:

    TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

对于第一种方式, 可以通过检查Java 进程的启动命令获得(这里假设pid是44848), 发现命令行没设置时区.

cat /proc/44848/cmdline

对于第二种方式, 我们首先通过查 看 cat /proc/44848/environ 的方式去查看, 没发现这个环境变量. 不过我们通过jdk 自带的命令的方式却发现了:

$ bin/jcmd 44848 VM.system_properties
java.version=1.8.0_342
user.timezone=America/Phoenix
sun.arch.data.model=64

虽然找到了系统环境变量, 却发现这里是正确的, 并不是Date.toString() 表现出的UTC 时区. 于是就只能检查是不是第三种设置的.

如何查看当前运行中的JVM里面的默认时区

  1. 可以通过 JVM attach agent的方式去查看, 要自己写个 Agent, 可以参考这个简单的 Agent: https://github.com/manecocomph/myJavaAgent/blob/962f424176e02b9638fec87a0a5d1bad9cfaf0b2/src/com/tianxiaohui/java/agent/SampleAgent.java
    当然, 你可以通过 Btrace 不安全的方式,找个容易控制的拦截点, 然后打印 默认时区.
  2. 另外一种方式就是直接做一个heap, 直接查看heap 里面的 Timezone 找个class的字段, 我们就采取了这种方式, 打开 heap dump, 找到这个 java.util.TimeZone 类, 然后查看其静态字段defaultTimezone, 直接可以看到被设置的时区.
    第一步找到这个类:

heap1.png
查看其 静态字段 defaultTimeZone
defaultTZ.png

找到代码

既然确认是通过代码设置默认时区, 那么直接搜索代码就找到了. 原来他们在最近的代码改动中, 有人为了某个feature, 直接修改了系统 TimeZone, 但是其本来只是想看看另外一个时区的时间.

标签: none

添加新评论