How to fix
The following two options are equivalent. Pick the one you find most appropriate for your situation.
WeekFields.ISO
WeekFields.of(Locale.GERMANY)
using the country, Germany, instead of the language, German.
Why is this happening? CLDR and country vs. language
Two differences are in play here:
- Different default locale data in different Java versions.
- As others have said, the difference between a language-only locale and a locale that includes country.
The definition of week schemes in different locales is part of the locale data. Java can get its locale data from up to four sources. Java included its own locale data from early versions, and these were the default up to Java 8. From Java 8 CLDR (Unicode Common Locale Data Repository) data were included too, and these became the default from Java 9. Which obviously has changed some functionality and broken some old code, as you have experienced. More precisely the defaults are:
- Java 8: JRE,SPI where JRE refers to Java’s own locale data.
- Java 9, 10 and 11: CLDR,COMPAT where CLDR is what is says and COMPAT just is the new name for JRE data.
The defaults can be overridden by setting the system property java.locale.providers
. So we can get the Java 8 behaviour in Java 9 and later by setting this property to COMPAT,SPI
. Conversely we can get the Java 10 behaviour in Java 8 by setting it to CLDR,JRE
. So at its base this is not so much a difference between Java versions, only between their defaults.
The change from Java to CLDR data is this: The Java locale data assigned week definitions to language-only locales (like German) based on where the language is mostly spoken. In contrast the CLDR philosophy is that you may speak any language in any country in the world, and you would rather base the choice of week scheme on country than on language. As a consequence locales that don’t specify a country (like German) all use the worldwide default week definition.
Why the worldwide default week definition is “Sunday, 1” in CLDR I don’t understand. As others I would have expected and preferred ISO, the international standard, “Monday, 4”. As I said in a comment I also found a note saying that this should be the case, but it still isn’t (at least not in the CLDR versions used in Java 8 through 11).
Java 9 is special
As you observed, on Java 9 with default locale data you get “Monday 4” from Locale.GERMAN
even though CLDR should be the first default. If on the other hand I set java.locale.providers
to CLDR
alone, I do get “Sunday 1” as in Java 10 and 11.
A possible explanation is that the CLDR version used in Java 9 does not include a week definition for German. So with the default providers, CLDR,COMPAT, Java falls back on COMPAT, which provides “Monday, 4” for German. When I use CLDR alone, it instead falls back on the worldwide base default, “Sunday, 1”. If this explanation is correct (which I cannot guarantee), it would seem that the CLDR data versions used in Java 10 and 11 do include a week definition for German.
Links
Documentation of LocaleServiceProvider
with information about locale data providers and specification of default providers:
CLDR links: