java.text.ParseException: Unparseable date: java.text.DateFormat.parse(DateFormat.java:579)

Never use SimpleDateFormat or DateTimeFormatter without a Locale

Since the given date-time is in English, you should use Locale.ENGLISH with your date-time parser; otherwise the parsing will fail in a system (computer, phone etc.) which is using a non-English type of locale.

Also, note that the date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.

Demo:

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

public class Main {
    public static void main(String[] args) {
        final String strDateTime = "24 Oct 2016 7:31 pm";
        DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                .parseCaseInsensitive()             // For case-insensitive (e.g. am, Am, AM) parsing 
                .appendPattern("d MMM uuuu h:m a")  // Pattern conforming to the date-time string
                .toFormatter(Locale.ENGLISH);       // Locale
        LocalDateTime ldt = LocalDateTime.parse(strDateTime, dtf);
        System.out.println(ldt);
    }
}

Output:

2016-10-24T19:31

By default, DateTimeFormatter#ofPattern uses the default FORMAT locale which the JVM sets during startup based on the host environment. Same is the case with SimpleDateFormat. I have tried to illustrate the problem through the following demo:

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

public class Main {
    public static void main(String[] args) {
        final String strDateTime = "24 Oct 2016 7:31 pm";           
        DateTimeFormatter dtfWithDefaultLocale = null;          

        System.out.println("JVM's Locale: " + Locale.getDefault());
        // Using DateTimeFormatter with the default Locale
        dtfWithDefaultLocale = getDateTimeFormatterWithDefaultLocale();
        System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
        System.out.println(
                "Parsed with JVM's default locale: " + LocalDateTime.parse(strDateTime, dtfWithDefaultLocale));

        // Setting the JVM's default locale to Locale.FRANCE
        Locale.setDefault(Locale.FRANCE);
        
        // Using DateTimeFormatter with Locale.ENGLISH explicitly (recommended)
        DateTimeFormatter dtfWithEnglishLocale = getDateTimeFormatterWithEnglishLocale();
        System.out.println("JVM's Locale: " + Locale.getDefault());
        System.out.println("DateTimeFormatter's Locale: " + dtfWithEnglishLocale.getLocale());
        LocalDateTime zdt = LocalDateTime.parse(strDateTime, dtfWithEnglishLocale);
        System.out.println("Parsed with Locale.ENGLISH: " + zdt);

        
        System.out.println("JVM's Locale: " + Locale.getDefault());
        // Using DateTimeFormatter with the default Locale
        dtfWithDefaultLocale = getDateTimeFormatterWithDefaultLocale();
        System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
        System.out.println(
                "Parsed with JVM's default locale: " + LocalDateTime.parse(strDateTime, dtfWithDefaultLocale));
    }
    
    static DateTimeFormatter getDateTimeFormatterWithDefaultLocale() {
        return new DateTimeFormatterBuilder()
                .parseCaseInsensitive()             
                .appendPattern("d MMM uuuu h:m a") 
                .toFormatter(); // Using default Locale
    }
    
    static DateTimeFormatter getDateTimeFormatterWithEnglishLocale() {
        return new DateTimeFormatterBuilder()
                .parseCaseInsensitive()             
                .appendPattern("d MMM uuuu h:m a") 
                .toFormatter(Locale.ENGLISH); // Using Locale.ENGLISH
    }
}

Output:

JVM's Locale: en_GB
DateTimeFormatter's Locale: en_GB
Parsed with JVM's default locale: 2016-10-24T19:31
JVM's Locale: fr_FR
DateTimeFormatter's Locale: en
Parsed with Locale.ENGLISH: 2016-10-24T19:31
JVM's Locale: fr_FR
DateTimeFormatter's Locale: fr_FR
Exception in thread "main" java.time.format.DateTimeParseException: Text '24 Oct 2016 7:31 pm' could not be parsed at index 3
    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.LocalDateTime.parse(LocalDateTime.java:492)
    at Main.main(Main.java:34)

The following demo, using SimpleDateFormat, is just for the sake of completeness:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class Main {
    public static void main(String[] args) throws ParseException {
        final String strDateTime = "24 Oct 2016 7:31 pm";
        SimpleDateFormat sdf = new SimpleDateFormat("d MMM yyyy h:m a", Locale.ENGLISH);
        Date date = sdf.parse(strDateTime);
        System.out.println(date);
    }
}

Output:

Mon Oct 24 19:31:00 BST 2016

Leave a Comment