Java 运行中的JVM是否检测到计算机的更改';什么时区?

Java 运行中的JVM是否检测到计算机的更改';什么时区?,java,jvm,Java,Jvm,我找不到任何具体的文档来回答这个问题 我编写了一些简单的测试代码,以了解在OS X 10.12上的Java 1.8上实际发生了什么: public static void main(String[] _args) throws InterruptedException { while (true) { int calendarTimezoneOffset = Calendar.getInstance().get(Calendar.ZONE_OFFSET);

我找不到任何具体的文档来回答这个问题

我编写了一些简单的测试代码,以了解在OS X 10.12上的Java 1.8上实际发生了什么:

public static void main(String[] _args) throws InterruptedException {
    while (true) {
        int calendarTimezoneOffset = Calendar.getInstance().get(Calendar.ZONE_OFFSET);
        System.out.println("calendarTimezoneOffset = " + calendarTimezoneOffset);

        ZoneOffset offset = ZonedDateTime.now().getOffset();
        System.out.println("offset = " + offset);

        Thread.sleep(1000);
    }
}
旧方式(日历)和新方式(Java8的日期和时间库)在JVM运行时都没有检测到我对操作系统时区所做的任何更改。我需要停止并启动代码以获取更改的时区

这是故意的吗?跨JVM实现和操作系统的这种行为可靠吗?

规范非常清楚它是如何获得时区的:

获取Java虚拟机的默认时区。如果缓存的 默认时区可用,将返回其克隆。否则 方法采取以下步骤来确定默认时区

  • 使用user.timezone属性值作为默认时区ID(如果可用)
  • 检测平台时区ID。平台时区的来源和ID映射可能因实现而异
  • 如果给定或检测到的时区ID未知,则使用GMT作为最后手段
将缓存根据ID创建的默认时区,并删除其克隆 返回。user.timezone属性值设置为 返回

文档说明该区域已缓存;此方法受user.timezone系统属性的影响,反之亦然

该规范还规定通过以下方式清除缓存:

如果zone为null,则清除缓存的默认时区

也就是说,要重新读取系统时区,您必须

  • 通过调用
    TimeZone.setDefault(null)
    清除时区缓存
  • 通过调用
    system.clearProperty(“user.timezone”);清除
    user.timezone
    system属性
  • 尝试以下测试:

        while (true) {
            TimeZone.setDefault(null);
            System.clearProperty("user.timezone");
    
            System.out.println("Offset = " + TimeZone.getDefault().getRawOffset() / 3600);
            System.out.println("Zone ID = " + System.getProperty("user.timezone"));
    
            Thread.sleep(1000);
        }
    

    我搜索了一些与此问题相关的JVM文档,但没有任何内容提到对底层操作系统的更改会传播到JVM

    我认为
    TimeZone
    类持有答案。如果查看它,您将看到有一个名为
    defaultTimeZone
    的私有变量,它保存日期/日历实例默认使用的时区。此变量在方法
    setDefaultZone
    setDefault
    中设置

    setDefaultZone
    方法是私有的,仅从从日期/日历构造函数调用的
    getDefaultRef
    调用。下面是它的代码:

    static TimeZone getDefaultRef() {
       TimeZone defaultZone = defaultTimeZone;
       if (defaultZone == null) {
          // Need to initialize the default time zone.
          defaultZone = setDefaultZone();
          assert defaultZone != null;
        }
        // Don't clone here.
        return defaultZone;
    }
    
    从这个方法可以明显看出,日期/日历的任何新实例都将使用已设置的日历实例,并且不会检查它是否与操作系统使用的相同

    setDefault
    方法非常简单,它只是将
    defaultTimeZone
    变量设置为一个新值

    public static void setDefault(TimeZone zone) {
       SecurityManager sm = System.getSecurityManager();
       if (sm != null) {
          sm.checkPermission(new PropertyPermission("user.timezone", write"));
       }
       defaultTimeZone = zone;
    }
    
    阅读此方法的文档时,您将阅读以下语句:
    如果zone为null,则缓存的默认时区将被清除
    。这意味着以后对
    getDefault
    getDefaultRef
    的调用将首先从
    user.timezone
    属性读取最新的OS时区。如果此属性为空,它将读取系统的实际时区

    知道了这一点,我认为可以安全地假设对OS时区的更改不会传播到默认时区,因为该值是缓存的,并且永远不会更新,除非客户端希望这样做。在我看来,有两种可能的方法:

  • 使用
    TimeZone.setDefault
    方法,同时将所需时区传递为新的默认时区
  • 使用以下代码将其设置为系统使用的值:

    System.setProperty(“user.timezone”,”);
    TimeZone.setDefault(空)


  • 哇,另一种方式,时区可以刺伤我们的背部…我认为这是一种假设,即计算机在单个程序运行期间不会在时区之间移动。虽然这已经不符合要求了。。。我认为当操作系统改变时区时,当前的JVM不会改变时区。(不是JVM,但可能值得检查Android是如何做到这一点的…)我认为这可以归类为JVM错误。JVM对时区一无所知(规范从未提及它们,VM也不需要这些信息),与时区有关的一切都是平台API的一部分,也就是说,它是在类中实现的,如
    java.util.Timezone
    java.util.Calendar
    java.time
    -packages`。但是我没有发现定义这些类在更改时区时的行为的任何东西,因此,虽然在VM运行时不更改默认时区似乎是当前Java实现的行为,但这是无法保证的。有人知道时区缓存的位置吗?@Laurent.B在静态字段中,好的,仅此而已,不在磁盘上?我可以看到你在时区来源中所说的,但我在时区中面临着奇怪的行为,这就是为什么我怀疑,但你一定是对的。非常感谢。