Search code examples
javadatetimelocalization

Determinate the precision (significant digits) of parsed temporal


I'm dealing with dynamic date format conversion between different chronology, such as convert 110/02 (in Minguo chronology) into 2021/02 (in ISO chronology) or reverse. Both the date and the pattern are given at runtime.

The chronology conversion require the temporal to be a full date, otherwise exception was thrown:

DateTimeFormatter isoFmt = DateTimeFormatter.ofPattern("[y/]MM").withChronology(IsoChronology.INSTANCE);
DateTimeFormatter rocFmt = DateTimeFormatter.ofPattern("[y/]MM").withChronology(MinguoChronology.INSTANCE);

// same chronology, works without issue
rocFmt.parse("110/02").query(rocFmt::format);
isoFmt.parse("2021/02").query(isoFmt::format);

// different chronology, exception thrown
rocFmt.parse("110/02").query(isoFmt::format);
isoFmt.parse("2021/02").query(rocFmt::format);

DateTimeException: Unable to apply override chronology 'Minguo' because the temporal object being formatted contains date fields but does not represent a whole date

Operation based on LocalDate (which use IsoChronology) are also failed:

rocFmt.parse("110/02").query(YearMonth::from);
rocFmt.parse("110/02").query(Month::from);

DateTimeException: Unable to obtain YearMonth from TemporalAccessor
Caused by: DateTimeException: Unable to obtain LocalDate from TemporalAccessor:

With DateTimeFormatterBuilder I can set default value for the missing parts to make it resolvable. For example, 02, 2021 will be parsed into 2021/02/01 by MM, yyyy with dayOfMonth default to 1, and 02-20, 2021 will be parsed into 2021/02/20 by MM-dd, yyyy.

However the day 1 was for conversion only and isn't wanted by us. To determine whether should I keep this part, I'm finding a way determining the precision or significant digits of parsed temporal.

Although I can check whether dayOfMonth(d) field exists before conversion, but the value can also be derived from dayOfYear(D) or dayOfWeek(E) with extra fields given.

Is there any way I can determinate the precision or significant digits, so that I can prevent someone turn date 2021/02 into 110/02/01?

PS. Let's put the case MM/dd aside.


Solution

  • This is not possible, sorry.

    On one hand your expectations are quite reasonable since the Roc/Minguo calendar system uses the same months as ISO. The difference between the two calendar system is just that year numbers differ by 1911. So conversion should be simple.

    On the other hand different calendar systems generally have got different months, so a month in one calendar system does not translate unambiguously to a month in the other system. Rather the month will very often overlap with two different months in the other system. Which is probably why Java refuses to convert a Roc month to an ISO month and vice versa.

    I understand that assuming a day of month (for example 1) feels like a hack. It could be the simple way through, though.