Timestamp can't be parsed Issue java.time.format.DateTimeParseException: Text '9/25/2020, 12:46:00 PM' could not be parsed at index 0

1.4k views Asked by At

I am attempting to capture the time before and after I check a timestamp value on a webpage and then confirm my timestamp falls in between those times. However, I'm struggling to convert my String timestamp into a comparable format in a clean way.

        Instant b4 = Instant.now();
                    
        //My code submites a file that then triggers the timestamp. I retrieve it as a string
        //exa string"9/25/2020, 11:03:18 AM"

        DateTimeFormatter dtf = DateTimeFormatter
                .ofPattern("MM/dd/yyyy, HH:mm:ss a")
                .withZone(ZoneId.systemDefault());
        Instant instantTimestamp = Instant.from(dtf.parse(timeStamp));

        Instant after = Instant.now();          

        if (instantTimestamp.isAfter(b4) && instantTimestamp.isBefore(after)) {
            testPass = true;
        }

        Assert.assertTrue(testPass);

My Error: java.time.format.DateTimeParseException: Text '9/25/2020, 12:46:00 PM' could not be parsed at index 0

2

There are 2 answers

0
Arvind Kumar Avinash On BEST ANSWER

There is a mismatch in the format for the month and its value in the string. The format is MM which specifies two digits but the value is 9 which is a single digit. You can use single letters for month, day, year, hour, minute, seconds etc. to accommodate all allowable numbers of digits. Also, I suggest you parse it in a case-insensitive way so that upper and lower case (e.g. AM and am) both can be accommodated.

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        // Given date-time string
        String dateTimeString = "9/25/2020, 12:46:00 PM";

        DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                                .parseCaseInsensitive()
                                .appendPattern("M/d/u, h:m:s a")
                                .toFormatter(Locale.ENGLISH);

        // Convert the given date-time string to LocalDateTime
        LocalDateTime ldt = LocalDateTime.parse(dateTimeString, dtf);
        System.out.println(ldt);

        // Convert to LocalDateTime Instant if required
        Instant instant = ldt.toInstant(ZoneOffset.UTC);
        System.out.println(instant);
    }
}

Output:

2020-09-25T12:46
2020-09-25T12:46:00Z

ONLINE DEMO

If the timezone to which this Date-Time belongs is different from UTC, convert it to Instant through ZonedDateTime e.g.

Instant instant = ldt.atZone(ZoneId.of("America/Los_Angeles")).toInstant();

Learn more about the modern Date-Time API from Trail: Date Time.

0
M. Justin On

The error is due to the format string being used. "MM" requires the month portion of the input string to be exactly two digits long, but "9" is only one digit. In other words, it works for "09/25/2020, 11:03:18 AM", but not for "9/25/2020, 11:03:18 AM".

What's needed here is "M", which doesn't require the value to be preceded by "0":

        DateTimeFormatter dtf = DateTimeFormatter
                .ofPattern("M/dd/yyyy, HH:mm:ss a")
                .withZone(ZoneId.systemDefault());

If the date should also be allowed to be a single digit and not 0-padded for days 0-9, the "M/d/yyyy, HH:mm:ss a" pattern should be used instead.

This is described the DateTimeFormatter Javadocs:

All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters. The following pattern letters are defined:

Symbol  Meaning                     Presentation      Examples
------  -------                     ------------      -------
[...]
 M/L     month-of-year               number/text       7; 07; Jul; July; J
[...]

Text: [...]

Number: If the count of letters is one, then the value is output using the minimum number of digits and without padding. Otherwise, the count of digits is used as the width of the output field, with the value zero-padded as necessary. [...]

Number/Text: If the count of pattern letters is 3 or greater, use the Text rules above. Otherwise use the Number rules above.

Since "M" uses the "number/text" presentation, and the count of its letters your format ("MM") is 2, then it requires exactly two digits for the month. Switching it to a single "M" causes it to use the minimum number of digits (one digit for months 1-9, and two digits for months 10-12).