Search code examples
javadatezoneddatetime

Create ZonedDateTime values with default values causes DateTimeParseException


my goal is create a method that parse dates from Strings, both string and pattern are given as parameters, but some of the date strings does not contain any time values, so in my method i set default time values to current time values stored in variable 'now', but i am having some troubles parsing dates like this 10 may 2020 7:15 am. the code i use to parse the dates looks like this

    @Test 
    public void patronFechaZDT(){
    String strFecha = "10 may 2020 7:15 am";
    ZonedDateTime now = ZonedDateTime.now();
            DateTimeFormatter dtf1 = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .appendPattern("dd MMMM yyyy h:mm a")
            .parseDefaulting(ChronoField.HOUR_OF_DAY, now.getHour())
            .parseDefaulting(ChronoField.MINUTE_OF_HOUR, now.getMinute())
            .parseDefaulting(ChronoField.SECOND_OF_MINUTE, now.getSecond())
            .toFormatter(Locale.US)
            .withZone(ZoneId.systemDefault());

    TemporalAccessor accessor = dtf1.parse(strFecha, new ParsePosition(0));
    ZonedDateTime fecha = ZonedDateTime.from(accessor);

    System.out.println("str: " + strFecha + ", fecha: " + fecha );
}

The output of the code above is

java.time.format.DateTimeParseException: Text '10 may 2020 7:15 am' could not be parsed: Conflict found: HourOfDay 16 differs from HourOfDay 7 while resolving  AmPmOfDay

I alrready noticed the problem is the default value 'HOUR_OF_DAY' which causes conflict with the hour captured in the string, and removing the line .parseDefaulting(ChronoField.HOUR_OF_DAY, now.getHour()), my code runs well

The main problem is that my method will recive a lot of patterns and strings, and some of this patterns will not contain time values, or zone values, and i really want to parse the dates using default time values, so if it is posile i want to keep the line .parseDefaulting(ChronoField.HOUR_OF_DAY, now.getHour()), thanks in advance.

Edit

As @akuzminykh sugested, i add the correct ChronoField CLOCK_HOUR_OF_AMPM and my DateTimeFormatter now looks like this:

    int hour = now.getHour(); int am = 0;
    if(hour > 12){
        hour = hour - 12;
        am = 1;
    }

    DateTimeFormatter dtf1 = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .appendPattern("dd MMMM yyyy hh:mm a")
            .parseDefaulting(ChronoField.AMPM_OF_DAY, am)
            .parseDefaulting(ChronoField.CLOCK_HOUR_OF_AMPM, hour)
            .parseDefaulting(ChronoField.HOUR_OF_DAY, now.getHour())
            .parseDefaulting(ChronoField.MINUTE_OF_HOUR, now.getMinute())
            .parseDefaulting(ChronoField.SECOND_OF_MINUTE, now.getSecond())
            .toFormatter(Locale.US)
            .withZone(ZoneId.systemDefault());

But, unless i coment the line .parseDefaulting(ChronoField.HOUR_OF_DAY... this new Formatter produces the same exception. Any help willl be apreciated


Solution

  • When you parse h, which is for clock-hour-of-am-pm (1-12) (see DateTimeFormatter), you of course have to use the correct ChronoField for your parseDefaulting. Check out ChronoField. What you need is ChronoField.CLOCK_HOUR_OF_AMPM.