I have
private static final DateTimeFormatter DATE_PATTERN = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd[ ]['T'][HH:mm:ss][.SSSSSS][.SSSSS][.SSSS][.SSS][.SS][.S][X]")
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.parseDefaulting(ChronoField.MILLI_OF_SECOND, 0)
.toFormatter()
.withZone(ZoneOffset.UTC); // assume incoming is UTC
used by
public static Function<String, String> getFormattedDate() {
return dateTime -> {
try {
ZonedDateTime timeRemoved =
ZonedDateTime.parse(dateTime, DATE_PATTERN).truncatedTo(ChronoUnit.DAYS);
return DateTimeFormatter.ofPattern(DISPLAY_DATE_PATTERN).format(timeRemoved);
} catch (Exception e) {
return null;
}
};
}
with a test that fails
public void test_data_patter_with_ms(){
String formattedDate = DateTimeUtil.getFormattedDate().apply("2021-04-24T06:57:06.850");
assertThat(formattedDate, is("2021-04-24T00:00:00Z"));
}
with the exception
java.time.format.DateTimeParseException: Text '2021-04-24T06:57:06.850' could not be parsed: Conflict found: NanoOfSecond 850000000 differs from NanoOfSecond 0 while resolving MilliOfSecond
If I comment out .parseDefaulting(ChronoField.MILLI_OF_SECOND, 0) it works, but I'm not really sure I understand why and I don't like fixing issues and not understanding the why I fixed it.
Note that the
Spattern specifier corresponds to theNANO_OF_SECONDfield. DocumentationTherefore, when you do
parseDefaulting(ChronoField.MILLI_OF_SECOND, 0), the default value 0 is always used. From the documentation ofparseDefaulting:In your case, it is always the case that
MILLI_OF_SECOND"has no associated value", because your pattern parses theNANO_OF_SECONDfield. There is noMILLI_OF_SECONDcomponent in your pattern in the first place!And only then comes the resolution step of the parsing process. This basically figures out the values of unknown fields from the known fields, and also checks that the values of the fields agree with each other. This is where the algorithm finds out that somehow your date has a
MILLI_OF_SECONDof 0 due to yourparseDefaultingcall, but also aNANO_OF_SECONDof 850000000 because of what's in your string. This is a contradiction, and so an exception is thrown.I think you should have called
parseDefaultingwithNANO_OF_SECONDinstead:This way, when any of the
.SSSoptions appear in the string, the default value won't be used.Side note:
It is possible to change your pattern so that it parses the
MILLI_OF_SECONDfield, usingappendValue: