-
Bug
-
Resolution: Not an Issue
-
P3
-
None
-
20
-
b21
-
generic
-
generic
***Although this issue had been closed as `not an issue`, the issue was addressed in JDK 23 (JDK-8324665)***
A DESCRIPTION OF THE PROBLEM :
We just hit a blocker trying to switch to JDK 20 at work. Generated date format strings changed, and we can not parse some date strings with JDK 20 that were generated with JDK 19 (or earlier), because now a non-breaking space is used in some places that just had a regular space before:
// using java.text.DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.ENGLISH)
// or java.time.format.DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).localizedBy(Locale.ENGLISH)
JDK 19: "3/23/23, 2:30 PM"
JDK 20: "3/23/23, 2:30[NBSP]PM"
As far as I can tell, this was a deliberate change: https://bugs.openjdk.org/browse/JDK-8284840
But this will cause trouble for anyone that writes out and parses dates using the JDKs built in DateFormats or DateTimeFormatters. It's especially bad where users can edit date strings in a form, since they certainly won't put a non-breaking space before the AM/PM.
We can't move to JDK 20 easily because of this; we need to analyse our entire code base and search for all DateFormat/DateTimeFormatter instances which might now use the non-breaking space, to replace them with explicit format strings for every locale we support.
I would guess that we are not the only people in the world that try to parse user-editable date strings.
REGRESSION : Last worked in version 19.0.2
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) use JDK 19 or earlier
2) created a DateFormat instance via DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.ENGLISH);
or a DateTimeFormatter instance via DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).localizedBy(Locale.ENGLISH))
3) use that to generate a date/time string of the form: "3/23/23, 2:29 PM" (contains no NBSP)
4) save that to a file "test.txt"
5) switch to JDK 20 or later
6) create a formatter instance like in step 2
7) read the date string from the file created in step 4
8) try to parse it with the formatter
4) parse
- create
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The string is parsed into a valid date
ACTUAL -
An Exception is thrown. Depending on which formatter class was used:
java.text.DateFormat
// Exception in thread "main" java.text.ParseException: Unparseable date: "3/23/23, 2:30 PM"
// at java.base/java.text.DateFormat.parse(DateFormat.java:399)
// at Scratch2.main(scratch_3.java:29)
java.time.format.DateTimeFormatter
// Exception in thread "main" java.time.format.DateTimeParseException: Text '3/23/23, 3:11 PM' could not be parsed at index 13
// at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2106)
// at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1934)
// at Scratch2.main(scratch_3.java:32)
---------- BEGIN SOURCE ----------
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.text.DateFormat;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Date;
import java.util.Locale;
// run with JDK 19
class Scratch {
public static void main(String[] args) throws Exception {
try (var writer = new BufferedWriter(new FileWriter("test.txt"))) {
var df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.ENGLISH);
var dateString = df.format(new Date(1679578205994L));
// var dateString = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).localizedBy(Locale.ENGLISH).format(LocalDateTime.now());
writer.append(dateString); // writes: "3/23/23, 2:29 PM"
writer.newLine();
}
}
}
// run with JDK 20
class Scratch2 {
public static void main(String[] args) throws Exception {
try (var reader = new BufferedReader(new FileReader("test.txt"))) {
var dateString = reader.readLine();
var df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.ENGLISH);
var date = df.parse(dateString); // BOOM
// Exception in thread "main" java.text.ParseException: Unparseable date: "3/23/23, 2:30 PM"
// at java.base/java.text.DateFormat.parse(DateFormat.java:399)
// at Scratch2.main(scratch_3.java:29)
// similar issue with DateTimeFormatter
var date2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).localizedBy(Locale.ENGLISH).parse(dateString); // BOOM
// Exception in thread "main" java.time.format.DateTimeParseException: Text '3/23/23, 3:11 PM' could not be parsed at index 13
// at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2106)
// at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1934)
// at Scratch2.main(scratch_3.java:32)
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
I was in contact with someone and was relayed the following options
1) take the time to adjust our code base to deal with NBSP in date formats
2) Use the legacy locale data by designating -Djava.locale.providers=COMPAT at the launcher command line. (This option limits some newer functionalities though.)
3) Ask Unicode CLDR to revert the format.
I suspect option 3 has little to no chance of success though, since the change in Unicode CLDR has been in place for a bit now, and JDK isn't the only software that tries to adhere to it.
FREQUENCY : always
A DESCRIPTION OF THE PROBLEM :
We just hit a blocker trying to switch to JDK 20 at work. Generated date format strings changed, and we can not parse some date strings with JDK 20 that were generated with JDK 19 (or earlier), because now a non-breaking space is used in some places that just had a regular space before:
// using java.text.DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.ENGLISH)
// or java.time.format.DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).localizedBy(Locale.ENGLISH)
JDK 19: "3/23/23, 2:30 PM"
JDK 20: "3/23/23, 2:30[NBSP]PM"
As far as I can tell, this was a deliberate change: https://bugs.openjdk.org/browse/JDK-8284840
But this will cause trouble for anyone that writes out and parses dates using the JDKs built in DateFormats or DateTimeFormatters. It's especially bad where users can edit date strings in a form, since they certainly won't put a non-breaking space before the AM/PM.
We can't move to JDK 20 easily because of this; we need to analyse our entire code base and search for all DateFormat/DateTimeFormatter instances which might now use the non-breaking space, to replace them with explicit format strings for every locale we support.
I would guess that we are not the only people in the world that try to parse user-editable date strings.
REGRESSION : Last worked in version 19.0.2
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) use JDK 19 or earlier
2) created a DateFormat instance via DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.ENGLISH);
or a DateTimeFormatter instance via DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).localizedBy(Locale.ENGLISH))
3) use that to generate a date/time string of the form: "3/23/23, 2:29 PM" (contains no NBSP)
4) save that to a file "test.txt"
5) switch to JDK 20 or later
6) create a formatter instance like in step 2
7) read the date string from the file created in step 4
8) try to parse it with the formatter
4) parse
- create
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The string is parsed into a valid date
ACTUAL -
An Exception is thrown. Depending on which formatter class was used:
java.text.DateFormat
// Exception in thread "main" java.text.ParseException: Unparseable date: "3/23/23, 2:30 PM"
// at java.base/java.text.DateFormat.parse(DateFormat.java:399)
// at Scratch2.main(scratch_3.java:29)
java.time.format.DateTimeFormatter
// Exception in thread "main" java.time.format.DateTimeParseException: Text '3/23/23, 3:11 PM' could not be parsed at index 13
// at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2106)
// at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1934)
// at Scratch2.main(scratch_3.java:32)
---------- BEGIN SOURCE ----------
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.text.DateFormat;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Date;
import java.util.Locale;
// run with JDK 19
class Scratch {
public static void main(String[] args) throws Exception {
try (var writer = new BufferedWriter(new FileWriter("test.txt"))) {
var df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.ENGLISH);
var dateString = df.format(new Date(1679578205994L));
// var dateString = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).localizedBy(Locale.ENGLISH).format(LocalDateTime.now());
writer.append(dateString); // writes: "3/23/23, 2:29 PM"
writer.newLine();
}
}
}
// run with JDK 20
class Scratch2 {
public static void main(String[] args) throws Exception {
try (var reader = new BufferedReader(new FileReader("test.txt"))) {
var dateString = reader.readLine();
var df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.ENGLISH);
var date = df.parse(dateString); // BOOM
// Exception in thread "main" java.text.ParseException: Unparseable date: "3/23/23, 2:30 PM"
// at java.base/java.text.DateFormat.parse(DateFormat.java:399)
// at Scratch2.main(scratch_3.java:29)
// similar issue with DateTimeFormatter
var date2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).localizedBy(Locale.ENGLISH).parse(dateString); // BOOM
// Exception in thread "main" java.time.format.DateTimeParseException: Text '3/23/23, 3:11 PM' could not be parsed at index 13
// at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2106)
// at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1934)
// at Scratch2.main(scratch_3.java:32)
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
I was in contact with someone and was relayed the following options
1) take the time to adjust our code base to deal with NBSP in date formats
2) Use the legacy locale data by designating -Djava.locale.providers=COMPAT at the launcher command line. (This option limits some newer functionalities though.)
3) Ask Unicode CLDR to revert the format.
I suspect option 3 has little to no chance of success though, since the change in Unicode CLDR has been in place for a bit now, and JDK isn't the only software that tries to adhere to it.
FREQUENCY : always
- duplicates
-
JDK-8324308 US DateTimeFormatter uses Narrow No-Break Space
-
- Closed
-
- relates to
-
JDK-8284840 Update CLDR to Version 42.0
-
- Resolved
-
-
JDK-8324665 Loose matching of space separators in the lenient date/time parsing mode
-
- Resolved
-
- links to