Unable to parse DateTime-string with AM/PM marker

The string I want to format looks like this: String datetime = "9/1/10 11:34:35 AM"

Following pattern for SimpleDateFormat works:

SimpleDateFormat sdf = SimpleDateFormat("M/d/yy h:mm:ss");
Date d = sdf.parse(datetime);
System.out.println(d);

Output> [Wed Sep 01 11:34:35 CEST 2010]

However I need to parse the AM/PM marker as well, and when I add that to the pattern I receive an exception.

Pattern that doesn't work:

SimpleDateFormat sdf = SimpleDateFormat("M/d/yy h:mm:ss a");

I have tried with this also with same exception:

SimpleDateFormat sdf = SimpleDateFormat("M/d/yy h:mm:ss aa");

Exception:

java.text.ParseException: Unparseable date: "9/1/10 11:34:35 AM"

I have looked through the API at http://download.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html#text but canät seem to find where I do wrong.

Any suggestions?


Solution 1:

One possibility is that your default Locale has different symbols for AM/PM. When constructing a date format you should always supply a Locale unless you really want to use the system's default Locale, e.g.:

SimpleDateFormat sdf = new SimpleDateFormat("M/d/yy h:mm:ss a", Locale.US)

Solution 2:

Modern answer:

    String datetime = "9/1/10 11:34:35 AM";
    LocalDateTime dt = LocalDateTime.parse(datetime, 
            DateTimeFormatter.ofPattern("M/d/yy h:mm:ss a", Locale.ENGLISH));

This produces a LocalDateTime of 2010-09-01T11:34:35. Beware of two digit years, though; DateTimeFormatter will assume 2000 through 2099. For my birthday this would have been incorrect.

We still need to provide the locale. Since AM/PM markers are hardly used in practice in other locales than English, I considered Locale.ENGLISH a fairly safe bet. Please substitute your own.

The other answers were fine answers in 2010 and 2011. Already in 2014 the above was valid and I would have preferred it.

Solution 3:

I am taking an example of date given below and print the formatted date into 24-hour format if suits your requirement.

 String inputdate="9/1/10 11:34:35 AM";
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("dd/MM/yy hh:mm:ss aa",Locale.getDefault());
        try {
            System.out.println(""+new SimpleDateFormat("dd/MM/yy HH:mm:ss",Locale.getDefault()).format(simpleDateFormat.parse(inputdate)));

        } catch (ParseException e) {
            e.printStackTrace();
        }

If you still have any query, Please respond. Thanks.

Solution 4:

java.time

You can build a case-insensitive parser using DateTimeFormatterBuilder. Since a date-time parsing/formatting type (e.g. DateTimeFormatter, SimpleDateFormat etc.) is Locale-sensitive, you should always use a Locale with such a type. I've used Locale.ENGLISH because your date-time string has AM/PM marker in English.

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

public class Main {
    public static void main(String args[]) {
        DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                                .parseCaseInsensitive()
                                .appendPattern("M/d/uu H:m:s a")
                                .toFormatter(Locale.ENGLISH);
        
        //Test
        Stream.of(
                "9/1/10 11:34:35 AM",
                "9/1/10 11:34:35 am",
                "09/1/10 11:34:35 AM",
                "9/01/10 11:34:35 Am"
        ).forEach(s -> System.out.println(LocalDateTime.parse(s, dtf)));;
    }
}

Output:

2010-09-01T11:34:35
2010-09-01T11:34:35
2010-09-01T11:34:35
2010-09-01T11:34:35

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


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.