Skip to content
Advertisement

java.time.format.DateTimeParseException: Text could not be parsed at index

This looks like a very simple thing to achieve, but I am failing to do so.

I have a string pattern which is yyyyMMddHH and I am trying to parse 2021061104 into an instance of LocalDateTime

Here is the code:

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;


class Main {
    public static void main(String[] args) {
        String pattern = "yyyyMMddHH";
        String date = "2021061104";
        DateTimeFormatter formatter =
            new DateTimeFormatterBuilder()
                .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                .parseLenient()
                .appendPattern(pattern)
                .toFormatter();
        LocalDateTime ldt = LocalDateTime.parse(date, formatter);
    }
}

It throws this exception:

Exception in thread "main" java.time.format.DateTimeParseException: Text '2021061104' could not be parsed at index 8
        at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
        at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
        at java.time.LocalDateTime.parse(LocalDateTime.java:492)
        at Main.main(Main.java:22)

It is failing to parse the HH field from the input.
I have looked at the javadoc here But that does not help.

Why do I have this exception? How to solve this?

EDIT:

I can not remove .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)

The following are the constraints:

  • The user will give the pattern and date ( might be as args[0] and args[1] )
  • The pattern must always have date ( Year Month and Date )
  • The time in the pattern is optional and it would be up to hour only.
  • Examples of a couple of valid patterns are: yyyy-MM-dd HH, yyyy MM dd

With these constraints, I can not remove .parseDefaulting(ChronoField.HOUR_OF_DAY, 0) because if I do so, I would not be able to parse yyyy-MM-dd into an instance of LocalDateTime here

Advertisement

Answer

Well, I think this is caused by the line with .parseDefaulting(ChronoField.HOUR_OF_DAY, 0). The builder immediately inserts a default value, before any parsing has taken place. At the time of parsing, the hour component already has a value, so the parsing of HH fails.

This behavior is actually mentioned in the JavaDocs:

During parsing, the current state of the parse is inspected. If the specified field has no associated value, because it has not been parsed successfully at that point, then the specified value is injected into the parse result. Injection is immediate, thus the field-value pair will be visible to any subsequent elements in the formatter. As such, this method is normally called at the end of the builder.

Emphasis mine.

So a possible fix would be to move the parseDefaulting lines to the end of the formatter builder:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .parseLenient()
    .appendPattern(pattern)
    .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
    .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
    .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
    .toFormatter();

Here is a working example with those lines moved to the end of the builder.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement