2

I am running the following tests to parse time in HH:mm am/pm format all 3 tests pass in Java 8 (1.8.0_282) but 2nd and 3rd test fail in latest Java 11_0_11 version, only the very simple test (first test without am/pm info) passed in Java 11. Also i am running Oracle JDK 11 as well as AdoptOpenJDK 11 with same results.

  • My Main Requirement

I have incoming JSON payload containing (as strings) before and after times with am/pm information. I need to parse Local Time out of them and then compare the local times against each other to see if one is before the other.

@Test
public void testLocalTime1() { //passed with java8 and java 11
    LocalTime localTime = LocalTime.parse("11:15", DateTimeFormatter.ofPattern("HH:mm"));
    System.out.println(localTime);
}

@Test
public void testLocalTime2() {//passed with java8 only, failed with java 11
    LocalTime test = LocalTime.parse("8:00 am".toUpperCase(),
            DateTimeFormatter.ofPattern("h:mm a"));
    System.out.println(test);

}

@Test
public void testLocalTime3() {//passed with java8 only, failed with java 11
    LocalTime test = LocalTime.parse("11:00 AM",
            DateTimeFormatter.ofPattern("HH:mm a"));
    System.out.println(test);

}

The error i am getting is

java.time.format.DateTimeParseException: Text '8:00 AM' could not be parsed at index 0

at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
at java.base/java.time.LocalTime.parse(LocalTime.java:463)
at com.company.SampleTest.testLocalTime2_1(SampleTest.java:45)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)

The version of Java 11 is latest

java -version

                             
java version "11.0.11" 2021-04-20 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.11+9-LTS-194)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.11+9-LTS-194, mixed mode)
Robin Bajaj
  • 2,002
  • 4
  • 29
  • 47
  • 2
    `HH` is for 24 hour time so the `a` doesn't make sense. use `h`. I can't explain #2 as it works for me but I'm using java 16. `LocalTime` has an i`sBefore` method so that part should be easy. – WJS May 26 '21 at 16:54
  • valid point @WJS - that's valid for testLocalTime3. but the testLocalTime2() is using h:mm a format so that should work. Its working for Java8 but does not work on Java 11. very strange – Robin Bajaj May 26 '21 at 17:03
  • unfortunately we are stuck with LTS releases only, for us its either Java11 or Java17 after that which is too far out .. for now Java 11 is the main milestone release we are upgrading to. – Robin Bajaj May 26 '21 at 17:04
  • 1
    Cannot reproduce with *openjdk 11 2018-09-25*, please provide the exact version to reproduce the problem and the error message. – samabcde May 26 '21 at 17:04
  • i have updated the main post with answers to your question @samabcde thx for looking into it – Robin Bajaj May 26 '21 at 17:23
  • Which is your default locale on each of the two Java installations? (Print `Locale.getDefault()`.) – Ole V.V. May 27 '21 at 05:48

1 Answers1

7

There are two problems in your code:

  1. You haven't used Locale with DateTimeFormatter which is a Locale-sensitive type. Never use SimpleDateFormat or DateTimeFormatter without a Locale.
  2. You have used H instead of h for 12-hour format. The symbol, H is used for 24-hour format.

Demo:

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                                .parseCaseInsensitive()
                                .appendPattern("h:m a")
                                .toFormatter(Locale.ENGLISH);

        System.out.println(LocalTime.parse("8:00 am", dtf));            
        System.out.println(LocalTime.parse("11:00 AM", dtf));
    }
}

Output:

08:00
11:00

Learn more about java.time, the modern Date-Time API* from Trail: Date Time.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110