Search code examples
javajava-time

Exception in thread "main" java.time.format.DateTimeParseException: Text 'Apr 1 2022 12:00:00:000AM' could not be parsed at index 19


I've date format like Apr 1 2022 12:00:00:000AM and looking to convert it into 20220401 (yyyyMMdd).How can we convert the Date format

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Demo {
    public static void main(String[] args) {
        String value = "Apr  1 2022 12:00:00:000AM";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM d yyyy hh:mm:ss.SSSa");
        LocalDateTime dateTime = LocalDateTime.parse(value, formatter);
        System.out.println(dateTime);
    }
}

When run this code giving me below error

Exception in thread "main" java.time.format.DateTimeParseException: Text 'Apr  1 2022 12:00:00:000AM' could not be parsed at index 4
    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
    at java.time.LocalDateTime.parse(LocalDateTime.java:492)
    at Demo.main(Demo.java:10)

EDIT-1 As per Basil Bourque suggestions, still below is not working

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Demo {
    public static void main(String[] args) {
        String value = "Apr  1 2022 12:00:00:000AM".replace( "  " , " " ) ;
        Locale locale = new Locale.Builder().setLanguage("en").setRegion("US").build();
        DateTimeFormatter formatter = 
                DateTimeFormatter.
                ofPattern("MMM d yyyy hh:mm:ss.SSSa")
                .withLocale( locale ) ;
        
        LocalDateTime dateTime = LocalDateTime.parse(value, formatter);
        System.out.println(dateTime);
    }
}

Still the same error

Exception in thread "main" java.time.format.DateTimeParseException: Text 'Apr 1 2022 12:00:00:000AM' could not be parsed at index 19

Solution

  • tl;dr

    • Your defined formatting pattern fails to match your input, in multiple ways.
    • Always specify a Locale when parsing localized text.
    • Where possible, use only ISO 8601 standard formats to exchange date-time values textually.

    SPACE character

    You have two SPACE characters between your first two parts. Replace with a single SPACE.

     String value = "Apr  1 2022 12:00:00:000AM".replace( "  " , " " ) ;
    

    Alternatively, you may indicate an optional SPACE in your formatting pattern with square brackets: [ ].

    COLON character

    Your formatting pattern says to expect a FULL STOP (.) character between second and the AM/PM. But your input string has a COLON (:) there.

    Change your formatting pattern to match your input.

    Locale

    Specify a Locale explicitly rather than implicitly relying upon the JVM’s current default.

    Locale locale = new Locale( "en" , "US" ) ;  // In Java 19+, use `Locale.of`. 
    DateTimeFormatter formatter = 
            DateTimeFormatter
            .ofPattern("MMM d yyyy hh:mm:ss:SSSa");
            .withLocale( locale ) ;
    

    The Locale specifies the human language and the cultural norms to be used in localization. This includes the spelling of the month name, and the use of punctuation.

    Generating text

    To generate text in your desired, extract a LocalDate to focus on the date without the time of day.

    LocalDate ld = myLocalDateTime.toLocalDate() ;
    

    Then define a formatter for your format.

    No need to define a custom formatter in your case. Your desired formatter complies with the “basic” form of the ISO 8601 standard format that minimizes punctuation. Java provides a constant for that particular format: BASIC_ISO_DATE.

    String output = ld.format( DateTimeFormatter.BASIC_ISO_DATE ) ;
    

    Example code

        String input = "Apr  1 2022 12:00:00:000AM".replace( "  " , " " ) ;
        Locale locale =new  Locale( "en" , "US" ) ;  // In Java 19+, use `Locale.of`. 
        DateTimeFormatter formatter = 
            DateTimeFormatter
            .ofPattern("MMM d yyyy hh:mm:ss:SSSa")
            .withLocale( locale );
        LocalDateTime ldt = LocalDateTime.parse( input , formatter ) ;
        LocalDate ld = ldt.toLocalDate();
        String output = ld.format( DateTimeFormatter.BASIC_ISO_DATE ) ;
        System.out.println( output ) ;
    

    See this code run at Ideone.com.

    ISO 8601

    Avoid parsing text in custom formats, and avoid parsing localized text.

    The international standard ISO 8601 defines clear, simple, reliable formats for exchanging date-time values as text. These are easily read by machine as well as by humans across cultures.

    The java.time classes use ISO 8601 by default when parsing/generating text.

    The ideal solution is to educate the publisher of your data about the benefits of using ISO 8601.

    Your input should be: 2022-04-01T00:00.