开发者

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 ht开发者_StackOverflow中文版tp://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?


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)


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.


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.


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.


If you are working with FreeMarker for Java and pop on this issue use below code. I had this problem, my locale set AM/PM as DE. Not sure why... <#setting locale="en_US">


Just a note about Locale:
the symbols used for AM/PM depend on Locale!

This affects parsing strings, eventually causing errors if the used AM/PM field does not match the predefined symbols. (obviously also affects formatting)

java.time.format.DateTimeFormatter and java.text.SimpleDateFormat accept an optional Locale when being created. If none is given. the systems default one is used.


Warning: using DateTimeFormatter the case of the AM/PM flag is also relevant when parsing, at least for some locales.

As an example, the Indian Locale requires the AM/PM flag being lowercase (am, pm), while some other locales (ROOT, ITALY, US, GERMANY) only accept uppercase AM/PM.

This throws DateTimeParseException: Text '2021-03-31 10:15:30 AM +05:30' could not be parsed at index 20

ZonedDateTime.parse("2021-03-31 10:15:30 AM +05:30",
                    DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss a Z", 
                                                new Locale("en", "IN"))) 

This results in 2021-03-31T10:15:30+05:30

ZonedDateTime.parse("2021-03-31 10:15:30 am +05:30",
                    DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss a Z", 
                                                new Locale("en", "IN")))

Using Locale.US, Locale.GERMANY or Locale.ROOT, the results are inverted.

Note: case of AM/PM does not matter when parsing with SimpleDateFormat (I am not recommending its use, I prefer DateTimeFormatter)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜