首页 > 解决方案 > WeekFields 在 JVM 8 和 JVM 10 上的不同行为

问题描述

我在这里有非常简单的程序:

 public static void main(String[] args) {
        LocalDate year = LocalDate.ofYearDay(2022, 100);
        System.out.println(year);

        System.out.println(WeekFields.of(Locale.GERMAN).weekOfYear());

        System.out.println(year.with(WeekFields.of(Locale.GERMAN).weekOfYear(), 0));
        System.out.println(year.with(WeekFields.of(Locale.GERMAN).weekOfYear(), 0).with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)));
    }

但它在 JVM 8 和 JVM 10 上的行为不同。问题似乎是WeekFields.of(Locale.GERMAN).weekOfYear().

在 JVM 10 上,我得到以下结果:

JVM 10

2022-04-10
WeekOfYear[WeekFields[SUNDAY,1]]
2021-12-19
2021-12-13

而在 JVM 8 上:

JVM 8

2022-04-10
WeekOfYear[WeekFields[MONDAY,4]]
2022-01-02
2021-12-27

为什么会这样?我是否在做一些可能导致未定义行为的事情?还是在某处指定了这种行为变化?

JVM10:

$ java -version
openjdk version "10.0.2" 2018-07-17
OpenJDK Runtime Environment (build 10.0.2+13-Ubuntu-1ubuntu0.18.04.4)
OpenJDK 64-Bit Server VM (build 10.0.2+13-Ubuntu-1ubuntu0.18.04.4, mixed mode)

JVM8

$ java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-8u191-b12-2ubuntu0.18.04.1-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)

编辑: JVM 9具有相同的行为JVM 8JVM 11行为JVM 10

编辑2:我实际上在github上找到了改变行为的提交->这里我很好奇为什么会改变。

标签: javajava-8jvmjava-10localdate

解决方案


这样的星期字段是高度本地化的,因此依赖于底层 JVM 的本地化资源,这些资源可以从一个版本更改为另一个版本。

我认为 JVM10 更正确,因为Locale.GERMAN它没有提到任何国家,所以 Java 简单地假设为美国(将这个国家作为世界标准处理有些问题,但 Java 也是如此)。

你应该更好地使用 Locale.GERMANY. 该国家确实确实将星期一用作一周的第一天(与美国从星期日开始用作后备相比,GERMAN后者只是一种语言而不是国家/地区。

更新——我对 CLDR 数据的研究:

后备国家/地区“001”(= 全球)的当前 CLDR 数据列表周定义(星期一为一周的第一天,1 = 日历年第一周的最少天数)。令人惊讶的是,这与美国的定义不同(星期日,1)。我认为,甲骨文只是做了自己的事情。就个人而言,我同意@Holger 的观点,并希望 ISO-8601 作为后备(星期一,4)。

但是,您可以通过设置以下系统属性(未测试)来恢复 JVM-10 机器上的 Java-8 行为:

java.locale.providers=COMPAT,CLDR,SPI

推荐阅读