Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Java DateTimeFormatter can't format its own parsed TemporalAccessor

I’m creating a simply DateTimeFormatter, but it can’t seem to read it’s own output. The reason I need to use the DateTimeFormatter directly and not LocalDate.format or YearMonth.format is that the code needs to be generic enough to handle different instances of DateTimeFormatter with completely different fields. The code below fails with: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra

DateTimeFormatter yearMonthFormatter = DateTimeFormatter.ofPattern("yyyyMM");
TemporalAccessor yearMonthTemp = yearMonthFormatter.parse("200102");
String formatted = yearMonthFormatter.format(yearMonthTemp); //fails here trying to format its own output

Is there any way to accomplish the above without having to know the contents of the datetime pattern? i.e. the string "yyyyMM" is not static, it will be passed as a parameter.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

What is happening here is that when you parse the string, an additional resolution phase happens, and turns the yyyy format specifier representing the "Year Of Era" temporal field into a "Year" temporal field in the returned TemporalAccessor, and you end up with (yearMonthTemp.toString()):

{Year=2001, MonthOfYear=2},ISO

When you format, the yyyy format specifier expects to format a "Year Of Era" temporal field, but the temporal accessor doesn’t have it, as you can clearly see above.

If one needed to change the format of a Temporal without knowing the formats head of time, eg from yyyyMM to MMM-yyyy, you would need two different DateTimeFormatters. The formatters would be completely compatible in terms of the fields that they parse and the temporal objects they produce.

If all you want to do is changing formats, you can set the resolver style to STRICT (by default this is SMART):

DateTimeFormatter.ofPattern("yyyyMM")
    .withResolverStyle(ResolverStyle.STRICT);

Though I cannot find documentation for this, I have found that this will prevent it from automatically changing "Year Of Era" to "Year" (which is typically denoted uuuu). From my testing, every parsed temporal field will be present in the result. Assuming that you have the same format specifiers in the formatting DateFormatter, it will get the same temporal fields successfully.

Note that this also means that you cannot easily get something like a YearMonth from this DateTimeFormatter, because YearMonth.parse/YearMonth.from expects a "Year". not "Year Of Era".

// does not work
System.out.println(YearMonth.from(yearMonthTemp));
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading