1

I am trying to parse strings in the format of "<year> <quarter>" ("2022 1", "2022 2") into java.time.LocalDate objects. The closest related question I could find is this, but there the author also has the month. If I try to use

DateTimeFormatter quarterFormatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy q")
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1).toFormatter();
LocalDate.parse("2022 2", quarterFormatter);

I get the error java.time.format.DateTimeParseException: (...) Unable to obtain LocalDate from TemporalAccessor: {Year=2022, QuarterOfYear=2, DayOfMonth=1} , which doesn't really make sense to me, since that is all the data required to figure out a calendar date. What am I doing wrong?

Also, as a related question, the original format is actually without a whitespace between the year and the quarter, but if I try to run

DateTimeFormatter quarterFormatter = new DateTimeFormatterBuilder()
.appendPattern("yyyyq")
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1).toFormatter();
LocalDate.parse("20222", quarterFormatter);

I get java.time.format.DateTimeParseException: Text '20222' could not be parsed at index 0. That is also confusing, since parsing from other formats seems to work even without separators.

  • 1
    "since that is all the data required to figure out a calendar date. " <- Not really. Year=2022, QuarterOfYear=2, DayOfMonth=1 could be 2022-04-01, or 2022-05-01 or 2022-06-01. A Quarter isn't a specific month. – OH GOD SPIDERS Apr 28 '22 at 11:13
  • 1
    Which day in that quarter do you want? What date do you expect to get for "2022 2"? – Sweeper Apr 28 '22 at 11:14
  • 1
    Simply `.parseDefaulting(IsoFields.DAY_OF_QUARTER, 1)` instead of the `parseDefaulting` call you have got. You will then get `2022-04-01`, the first day of the 2nd quarter. – Ole V.V. Apr 28 '22 at 11:29
  • 3
    `DateTimeFormatter` is not good at separating `yyyy` fields from other fields. For your related question of `20222` you may use `new DateTimeFormatterBuilder() .appendValue(ChronoField.YEAR, 4) .appendValue(IsoFields.QUARTER_OF_YEAR, 1) .parseDefaulting(IsoFields.DAY_OF_QUARTER, 1) .toFormatter()`. – Ole V.V. Apr 28 '22 at 11:33
  • Thank you @OleV.V., I didn't think of using the IsoFields class. – Matei Macoveiciuc Apr 28 '22 at 11:56

2 Answers2

3

Here's a compilation of the information given in the comments:

Why do I get the Unable to obtain LocalDate message? And how to fix it?

That is because the parser does not have all necessary information, as OH GOD SPIDERS already said:

Not really. Year=2022, QuarterOfYear=2, DayOfMonth=1 could be 2022-04-01, or 2022-05-01 or 2022-06-01. A Quarter isn't a specific month.

How to fix it, was mentioned by Ole V.V.:

Simply .parseDefaulting(IsoFields.DAY_OF_QUARTER, 1) instead of the parseDefaulting call you have got. You will then get 2022-04-01, the first day of the 2nd quarter.

How do I fix the Text '20222' could not be parsed at index 0 error?

As mentioned by Ole V.V.:

DateTimeFormatter is not good at separating yyyy fields from other fields. For your related question of 20222 you may use

new DateTimeFormatterBuilder()
    .appendValue(ChronoField.YEAR, 4)
    .appendValue(IsoFields.QUARTER_OF_YEAR, 1)
    .parseDefaulting(IsoFields.DAY_OF_QUARTER, 1)
    .toFormatter()

(Formatting mine.)

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
2

@OleV.V.'s comment contains the right solution of using .parseDefaulting(IsoFields.DAY_OF_QUARTER, 1).