-
Notifications
You must be signed in to change notification settings - Fork 38.4k
Date and Time Formatting with JDK 20 and higher
This Wiki page discusses date/time formatting and parsing issues that developers may encounter when running their applications on JDK 20+.
Specifically, this document provides background information on changes in the JDK as well as guidance on how to address formatting and parsing issues encountered in Spring applications.
Before you read any further, we highly recommend that you first read JEP 252: Use CLDR Locale Data by Default.
Although this document primarily focuses on issues related to time formats for the US English locale (for example, 3:30 PM
), numerous other use cases may potentially be affected by locale-sensitive date/time formats provided by the Unicode Common Locale Data Repository (CLDR) project.
JDK 20 adopted Unicode CLDR 42 which includes CLDR-14032 that changed the space character that precedes the period
(AM or PM) in formatted date/time text from a standard space (" "
) to a narrow non-breaking space (NNBSP: "\u202F"
). Consequently, applications that rely on date/time parsing and formatting may encounter incompatible changes in behavior when using Spring on JDK 20 or higher – for example, web applications that make use of Spring Framework's @DateTimeFormat
support.
On JDK 20, 21, and 22, applications can use the -Djava.locale.providers=COMPAT
command-line argument for the java
compiler in order to force the use of legacy locale data which uses a standard space for the space character that precedes the period
in formatted date/time text.
Note, however, that the aforementioned COMPAT
mode has been removed in JDK 23.
It is also worth pointing out that string represenations of date/time formats can no longer be reliably encoded with ISO-8859-1 (latin-1) encoding. The reason is that characters such as a narrow non-breaking space ("\u202F"
) can only be properly represented with UTF encoding.
Consequently, developers and frameworks must find a way to either avoid or deal with locale-sensitive date/time formats provided by both current and future versions of the Unicode CLDR.
The Spring team recommends the use of ISO standardized formats for both parsing and formatting of date/time values whenever possible. For example, consider using a predefined iso
pattern in Spring's @DateTimeFormat
annotation (such as ISO.DATE_TIME
) or one of the ISO_*
constants defined in java.time.format.DateTimeFormatter
(such as ISO_DATE_TIME
) for programmatic handling of JSR-310 java.time
value types.
If using an ISO standardized format is not an option for your use case, consider one of the lenient approaches outlined below.
The Spring team also recommends the use of UTF encoding whenever possible – for example, UTF-8
.
TODO
TODO
In JDK 23, the Java team introduced support for lenient parsing of space characters in SimpleDateFormat
as well as DateTimeFormatter
.
SimpleDateFormat
is lenient by default; however, DateTimeFormatter
instances are not lenient by default, and factory methods like DateTimeFormatter.ofLocalizedTime(...)
do not create lenient formatters.
To create a lenient DateTimeFormatter
, one must forgo the use of the static factory methods in DateTimeFormatter
and instead make use of the DateTimeFormatterBuilder
. The following example shows how to create a static factory method for a lenient DateTimeFormatter
that is comparable to what DateTimeFormatter.ofLocalizedDateTime(FormatStyle, FormatStyle)
produces.
pubic static DateTimeFormatter createLenientDateTimeFormatter(
FormatStyle dateStyle, FormatStyle timeStyle) {
return new DateTimeFormatterBuilder()
.parseLenient()
.appendLocalized(dateStyle, timeStyle)
.toFormatter()
.withChronology(IsoChronology.INSTANCE);
}
- https://openjdk.org/jeps/252
- https://jdk.java.net/20/release-notes#JDK-8284840
- https://cldr.unicode.org/downloads/cldr-42
- https://unicode-org.atlassian.net/browse/CLDR-14032
- https://bugs.openjdk.org/browse/JDK-8223587
- https://bugs.openjdk.org/browse/JDK-8284840
- https://bugs.openjdk.org/browse/JDK-8297316
- https://bugs.openjdk.org/browse/JDK-8304925
- https://bugs.openjdk.org/browse/JDK-8324665
- https://github.com/spring-projects/spring-framework/issues/30185
- https://github.com/spring-projects/spring-framework/issues/33144
- https://github.com/spring-projects/spring-framework/issues/30649
- https://github.com/spring-projects/spring-framework/issues/33151
- https://github.com/spring-projects/spring-boot/issues/42430