Initial draft

See gh-33151
master
Sam Brannen 1 year ago
parent
commit
72cc66611e
  1. 78
      Date-and-Time-Formatting-with-JDK-20-and-higher.md

78
Date-and-Time-Formatting-with-JDK-20-and-higher.md

@ -1,3 +1,77 @@ @@ -1,3 +1,77 @@
This is a placeholder for forthcoming documentation regarding and date and time parsing and formatting issues with JDK 20+
## Overview
See https://github.com/spring-projects/spring-framework/issues/33151
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](https://openjdk.org/jeps/252).
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](https://cldr.unicode.org/).
## Background
JDK 20 adopted Unicode [CLDR 42](https://cldr.unicode.org/downloads/cldr-42) which includes [CLDR-14032](https://unicode-org.atlassian.net/browse/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.
## Recommendations
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`.
### Lenient `@DateTimeFormat` Configuration
TODO
### Lenient Parsing in Tests and Application Code
TODO
### Lenient `SimpleDateFormat` and `DateTimeFormatter` Configuration
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.
```java
pubic static DateTimeFormatter createLenientDateTimeFormatter(
FormatStyle dateStyle, FormatStyle timeStyle) {
return new DateTimeFormatterBuilder()
.parseLenient()
.appendLocalized(dateStyle, timeStyle)
.toFormatter()
.withChronology(IsoChronology.INSTANCE);
}
```
## Resources
- 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
## Related Spring Issues
- 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

Loading…
Cancel
Save