I am trying to port some code from joda time to java time.
JodaTime had the possibility to specify a fallback value for the year like this
parser.withDefaultYear((new DateTime(DateTimeZone.UTC)).getYear()).parseDateTime(text);
Regardless how the parser looks (if it includes a year or not), this will be parsed.
java.time has become much more stricter there. Even though there is the DateTimeFormatterBuilder.parseDefaulting()
method, which allows you to specify fallbacks, this only works if that specific field is not specified in the date your want to parse or is marked as optional.
If you do not have any control about the incoming date format, as it is user supplied, this makes it super hard when to call parseDefaulting
.
Is there any workaround, where I can specify something like either a generic fallback date, whose values get used by the formatter, if they are not specified or how I configure fallback values that are simply not used, when they are specified in the formatter?
Minimal, complete and verifiable example follows.
public static DateTimeFormatter ofPattern(String pattern) {
return new DateTimeFormatterBuilder()
.appendPattern(pattern)
.parseDefaulting(ChronoField.YEAR, 1970)
.toFormatter(Locale.ROOT);
}
public void testPatterns() {
// works
assertThat(LocalDate.from(ofPattern("MM/dd").parse("12/06")).toString(), is("1970-12-06"));
assertThat(LocalDate.from(ofPattern("uuuu/MM/dd").parse("2018/12/06")).toString(), is("2018-12-06"));
// fails with exception, as it uses year of era
assertThat(LocalDate.from(ofPattern("yyyy/MM/dd").parse("2018/12/06")).toString(), is("2018-12-06"));
}
Desired result: The test should parse the strings and pass (“be green”).
Observed result: The last line of the test throws an exception with the following message and stack trace.
Text '2018/12/06' could not be parsed: Conflict found: Year 1970 differs from Year 2018
Exception in thread "main" java.time.format.DateTimeParseException: Text '2018/12/06' could not be parsed: Conflict found: Year 1970 differs from Year 2018
at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1959)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1820)
at com.ajax.mypackage.MyTest.testPatterns(MyTest.java:33)
Caused by: java.time.DateTimeException: Conflict found: Year 1970 differs from Year 2018
at java.base/java.time.chrono.AbstractChronology.addFieldValue(AbstractChronology.java:676)
at java.base/java.time.chrono.IsoChronology.resolveYearOfEra(IsoChronology.java:620)
at java.base/java.time.chrono.IsoChronology.resolveYearOfEra(IsoChronology.java:126)
at java.base/java.time.chrono.AbstractChronology.resolveDate(AbstractChronology.java:463)
at java.base/java.time.chrono.IsoChronology.resolveDate(IsoChronology.java:585)
at java.base/java.time.chrono.IsoChronology.resolveDate(IsoChronology.java:126)
at java.base/java.time.format.Parsed.resolveDateFields(Parsed.java:360)
at java.base/java.time.format.Parsed.resolveFields(Parsed.java:266)
at java.base/java.time.format.Parsed.resolve(Parsed.java:253)
at java.base/java.time.format.DateTimeParseContext.toResolved(DateTimeParseContext.java:331)
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1994)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1816)
... 1 more
DateTimeFormatterBuilder
as you showed. Do you want overrides on certain parts of the date-time values? Adjust by calling thewith…
methods on the date-time object instantiated by theDateTimeFormatter
. Edit your Question to clarify defaults versus overrides. Perhaps give some examples of inputs and desired outputs. – Pettifoggingdd/MM
, then I would need to addparseDefaulting(ChronoField.YEAR, 1984)
to my formatter, knowing this format does not have a year. If the next parsing (note I do not know about the formatters, suer supplied) isYYYY/dd/MM
then addingparseDefaulting(ChronoField.YEAR, 1984)
will return an exception as the year is already set. So I need to somehow distinguish between those date formats to be able to set the proper default values. Hope that makes sense. – Subtlejava.time.format.DateTimeParseException: Text '2018/12/06' could not be parsed: Conflict found: Year 1970 differs from Year 2018
from the last one of your examples. The formatter has fields year, era and year-of-era. I believe thatparseDefaulting
will fill in a field if that specific field has not been parsed, no matter that it could have been deduced from other fields. I don’t know the solution. – UnreeveDateTimeFormatter.parseUnresolved()
orDateTimeFormatter.withResolverFields()
. It is not obvious. – Unreeveyyyy.MM.dd
or dashesyyyy-MM-dd
.. I think this would be supercomplex with a regex, as you would need to search for the letters (and count them), not for the characters in between, basically rebuilding the java time parsing logic – Subtle