1

My parser may encounter "2:37PM" (parsed by "H:mma") or "02:37PM" (parsed by "hh:mma"). How can I parse both without resorting to a try-catch?

I receive an error like this when I get it wrong:

Conflict found: Field AmPmOfDay 0 differs from AmPmOfDay 1 derived from 02:37

3
  • It's probably a good idea showing the code you used because only a small description and a contextless error msg is not a minimal reproducible example Commented May 15, 2020 at 13:31
  • It's also probably a good idea to know exactly what those pattern letters mean: The error is most likely caused by "2:37PM" getting parsed using a pattern with a capital H plus an a. If you are using a capital H, you don't really need that a in the pattern. Parse the first one with "h:mma" instead of "H:mma" or leave the a at the end, which will parse it to "14:37"! Commented May 15, 2020 at 13:43
  • Does this answer your question? Problem with parse a LocalDateTime using java 8 And/or this? Commented May 15, 2020 at 14:56

5 Answers 5

6

First of all, the error you get is caused by the H in your pattern, which parses hours in 24-hour format and gets into trouble if you put an a (for AM/PM) at the end of the pattern.

You can use java.time to parse the Strings to LocalTimes using a DateTimeFormatter that considers both of the patterns:

public static void main(String[] args) {
    // define a formatter that considers two patterns
    DateTimeFormatter parser = DateTimeFormatter.ofPattern("[h:mma][hh:mma]");
    // provide example time strings
    String firstTime = "2:37PM";
    String secondTime = "02:37PM";
    // parse them both using the formatter defined above
    LocalTime firstLocalTime = LocalTime.parse(firstTime, parser);
    LocalTime secondLocalTime = LocalTime.parse(secondTime, parser);
    // print the results
    System.out.println("First:\t" + firstLocalTime.format(DateTimeFormatter.ISO_TIME));
    System.out.println("Second:\t" + secondLocalTime.format(DateTimeFormatter.ISO_TIME));
}

The output of this is

First:  14:37:00
Second: 14:37:00

But it turned out you only need one pattern (which is better to have than two in a DateTimeFormatter anyway) because the h is able to parse hours of one or two digits. So the following code produces exactly the same output as the one above:

public static void main(String[] args) {
    // define a formatter that considers hours consisting of one or two digits plus AM/PM
    DateTimeFormatter parser = DateTimeFormatter.ofPattern("h:mma");
    // provide example time strings
    String firstTime = "2:37PM";
    String secondTime = "02:37PM";
    // parse them both using the formatter defined above
    LocalTime firstLocalTime = LocalTime.parse(firstTime, parser);
    LocalTime secondLocalTime = LocalTime.parse(secondTime, parser);
    // print the results
    System.out.println("First:\t" + firstLocalTime.format(DateTimeFormatter.ISO_TIME));
    System.out.println("Second:\t" + secondLocalTime.format(DateTimeFormatter.ISO_TIME));
}
Sign up to request clarification or add additional context in comments.

2 Comments

This is a more instructive answer than the "it worked" that I found. Thanks!
@WebdevTory nice... But keep in mind that you are allowed to use a DateTimeFormatter defined like this for output, but the downside is that it would then output the time concatenating both patterns. So define an extra one for LocalTime.format() if you want to output them or use a built-in as I did in this example.
3

You did say you wanted to parse the string. So you can do the following.

for (String s : new String[] { "02:37PM", "2:37PM" }) {
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("h:mma");
    LocalTime lt = LocalTime.parse(s, dtf);
    System.out.println(lt.format(dtf));
}

Prints

2:37PM
2:37PM

Comments

1

You can create a string for the hours and have an if statement to check whether the hours is < 10 (single digit) then prepend "0".

Comments

1

You can use String#format with %02d on the hour portion of the String. This will pad the value with 0 until its size 2. We can then replace the original hour portion with the formatted portion.

        String timeLiteral = "2:37PM";

        String originalHour = timeLiteral.split(":")[0];

        String formattedHour = String.format("%02d", Integer.parseInt(originalHour));

        String result = timeLiteral.replace(originalHour, formattedHour);

Comments

0

To my surprise, it looks like the answer was formatter "h:mma", which actually discerns correctly between one- and two-digit hour specifications and even catches technically dubious times like "02:38 PM" (which should probably not have a leading 0, but tell it to my data sources...)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.