My program recognizes dates of various formats in a broken JSON and replaces them with ISO8601. Then the JSON is passed to a 3rd-party library.
One of the formats has no time and is supposed to be parsed as 00:00:00, but parsing a seemingly valid date string fails with Unable to obtain LocalTime from TemporalAccessor
.
public static void main(String[] args) throws Exception {
DateTimeFormatter standardFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US).withZone(ZoneOffset.UTC );
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.US).withZone(ZoneOffset.UTC );
ZonedDateTime utcDateTime = ZonedDateTime.parse("2022-11-23" , df);
System.out.println( utcDateTime.format(standardFormatter) );
}
_
Exception in thread "main" java.time.format.DateTimeParseException: Text '2022-11-23' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {},ISO,Z resolved to 2022-11-23 of type java.time.format.Parsed
at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:2017)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
at java.base/java.time.ZonedDateTime.parse(ZonedDateTime.java:598)
at bookproposal.actions.FixupDates.main(FixupDates.java:107)
Caused by: java.time.DateTimeException: Unable to obtain ZonedDateTime from TemporalAccessor: {},ISO,Z resolved to 2022-11-23 of type java.time.format.Parsed
at java.base/java.time.ZonedDateTime.from(ZonedDateTime.java:566)
at java.base/java.time.format.Parsed.query(Parsed.java:235)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
... 2 more
Caused by: java.time.DateTimeException: Unable to obtain LocalTime from TemporalAccessor: {},ISO,Z resolved to 2022-11-23 of type java.time.format.Parsed
at java.base/java.time.LocalTime.from(LocalTime.java:431)
at java.base/java.time.ZonedDateTime.from(ZonedDateTime.java:561)
... 4 more
CodePudding user response:
The answer is calling parseDefaulting on the DF builder and here's the instruction how to use it: https://stackoverflow.com/a/40593213/447503
public static void main(String[] args) throws Exception {
DateTimeFormatter standardFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US)
.withZone(ZoneOffset.UTC);
DateTimeFormatter df = makeDateTimeFormatter("yyyy-MM-dd", true);
ZonedDateTime utcDateTime = ZonedDateTime.parse("2022-11-23", df);
System.out.println(utcDateTime.format(standardFormatter));
}
private static DateTimeFormatter makeDateTimeFormatter(String formatStr, boolean dateOnly) {
final DateTimeFormatterBuilder builder1 = new DateTimeFormatterBuilder().appendPattern(formatStr);
final DateTimeFormatterBuilder builder2 = !dateOnly ? builder1
: builder1.parseDefaulting(ChronoField.HOUR_OF_DAY, 0).parseDefaulting(ChronoField.MINUTE_OF_DAY, 0);
DateTimeFormatter df = builder2.toFormatter(Locale.US).withZone(ZoneOffset.UTC);
return df;
}
CodePudding user response:
You're trying to format a time while only providing a date. That way, the formatter has no idea what time to choose and fails.
Instead, give the ZonedDateTime an actual time aswell, like this: ZonedDateTime.parse("2022-11-23 00:00:00.000", df)
You're going to have to change the format aswell: yyyy-MM-dd HH:mm:ss.SSS
CodePudding user response:
Your String '2022-11-23' does not conform to your format "yyyy-MM-dd'T'HH:mm:ss.SSSX". According to your format it is expected that at the end of your string there will be continuation such as "T12:23:12.122..." since it doesn't find it the parsing fails and that is expected behavior. I assume that when you parse your Strings you may encounter strings in different formats ands you need to parse them all. Here is the idea: create a list of all the formats that you want to support (it may come from property file for example) and when a String comes try to parse it with formats from your list one by one until you successfully parse the string with one of them. Note that in this case the order of the formats may be important in case you need to support US and European formats ("MM-dd-yyyy" and "dd-MM-yyyy" as say the date "01-02-2022" may be interpreted as Jan 2d or Feb 1st.) Anyway, I wrote an article about this issue with full explanation of this idea. Take a look at Java 8 java.time package: parsing any string to date