-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

Webdev Tory
  • 435
  • 3
  • 13
  • It's probably a good idea showing the code you used because only a small description and a contextless error msg is not a [mcve] – fuggerjaki61 May 15 '20 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"`! – deHaar May 15 '20 at 13:43
  • Does this answer your question? [Problem with parse a LocalDateTime using java 8](https://stackoverflow.com/questions/58886514/problem-with-parse-a-localdatetime-using-java-8) And/or [this](https://stackoverflow.com/questions/61791762/is-there-master-date-time-pattern-which-will-work-for-every-similar-date-time-pa)? – Ole V.V. May 15 '20 at 14:56

5 Answers5

4

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));
}
deHaar
  • 17,687
  • 10
  • 38
  • 51
  • 1
    This is a more instructive answer than the "it worked" that I found. Thanks! – Webdev Tory May 15 '20 at 13:48
  • @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. – deHaar May 15 '20 at 13:50
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

WJS
  • 36,363
  • 4
  • 24
  • 39
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".

Youstanzr
  • 605
  • 1
  • 8
  • 16
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);
Jason
  • 5,154
  • 2
  • 12
  • 22
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...)

Webdev Tory
  • 435
  • 3
  • 13