Synesso Synesso - 1 month ago 32
Java Question

DateTimeFormatter can parse, but not format for same input

The

DateTimeFormatter
for pattern
"yyyy_'w'w"
is unable to format the value it has parsed.

val df = DateTimeFormatter.ofPattern("yyyy_'w'w")
df: DateTimeFormatter = Value(YearOfEra,4,19,EXCEEDS_PAD)'_''w'Localized(WeekOfWeekBasedYear,1)

val week = df.parse("2017_w19")
week: temporal.TemporalAccessor = {Year=2017, WeekOfWeekBasedYear[WeekFields[SUNDAY,1]]=19},ISO

df.format(week)


The error is:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
java.time.format.Parsed.getLong(Parsed.java:203)
java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
java.time.format.DateTimeFormatterBuilder$NumberPrinterParser.format(DateTimeFormatterBuilder.java:2540)
java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2179)
java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1746)
java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1720)


Why is this?

Answer Source

The pattern yyyy represents the year-of-era field. But according to javadoc, there's also the pattern uuuu to represent the year field (read those links to see the small difference between them - although for current dates there's not much difference).

The problem is: when you create a formatter with y, it uses the year-of-era field, as you can see by the value:

Value(YearOfEra,4,19,EXCEEDS_PAD)

But when parsing, the resulting parsed object (in your case, the week variable) is created with the year field - as you can see by the value:

{Year=2017, ...


The formatter is set with the year-of-era field. So when you try to format week, it tries to get this field from the week variable. As this field doesn't exist (week contains only year, but not year-of-era), it throws the UnsupportedTemporalTypeException.

The solution is to use the year field (the u pattern) in the formatter:

val df = DateTimeFormatter.ofPattern("uuuu_'w'w")
println(df)
val week = df.parse("2017_w19")
println(week)
println(df.format(week))

The output will be:

Value(Year,4,19,EXCEEDS_PAD)'_''w'Localized(WeekOfWeekBasedYear,1)
{Year=2017, WeekOfWeekBasedYear[WeekFields[SUNDAY,1]]=19},ISO
2017_w19

Note that now the formatter was created with the year field, and the format method now tries to get this field from the parsed object, and no exception is thrown.