23

我要格式化的字符串如下所示: String datetime = "9/1/10 11:34:35 AM"

SimpleDateFormat 的以下模式有效:

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]

但是,我还需要解析 AM/PM 标记,当我将其添加到模式中时,我会收到异常。

不起作用的模式:

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

我也试过这个,但有同样的例外:

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

例外:

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

我在http://download.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html#text查看了 API,但似乎找不到我做错的地方。

有什么建议么?

4

6 回答 6

44

一种可能性是您的默认值Locale具有不同的 AM/PM 符号。在构造日期格式时,您应该始终提供 a Locale,除非您真的想使用系统的默认值Locale,例如:

SimpleDateFormat sdf = new SimpleDateFormat("M/d/yy h:mm:ss a", Locale.US)
于 2010-09-01T13:56:47.163 回答
6

现代答案:

    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));

这会产生LocalDateTime2010-09-01T11:34:35。不过要注意两位数的年份;DateTimeFormatter将假设从 2000 年到 2099 年。对于我的生日,这将是不正确的。

我们仍然需要提供语言环境。由于 AM/PM 标记在英语以外的其他语言环境中几乎不使用,因此我认为这是Locale.ENGLISH一个相当安全的选择。请换成你自己的。

其他答案在 2010 年和 2011 年都是很好的答案。在 2014 年以上已经是有效的,我会更喜欢它。

于 2017-06-16T19:18:26.513 回答
3

我以下面给出的日期为例,如果符合您的要求,将格式化的日期打印为 24 小时格式。

 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();
        }

如果您仍有任何疑问,请回复。谢谢。

于 2014-11-27T11:43:09.247 回答
1

java.time

您可以使用构建一个不区分大小写的解析器DateTimeFormatterBuilder。由于日期时间解析/格式化类型(例如DateTimeFormatterSimpleDateFormat等)是 -Locale敏感的,因此您应该始终将 aLocale与此类类型一起使用。我使用过Locale.ENGLISH是因为您的日期时间字符串有英文的 AM/PM 标记。

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)));;
    }
}

输出:

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

Trail: Date Time了解有关现代日期时间 API *的更多信息。


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,则可以使用ThreeTen-Backport,它将大部分java.time功能向后移植到 Java 6 和 7。如果您正在为 Android 项目和 Android API 工作level 仍然不符合 Java-8,请检查Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

于 2021-04-30T22:02:23.520 回答
0

如果您正在使用 FreeMarker for Java 并在此问题上弹出,请使用以下代码。我遇到了这个问题,我的语言环境将 AM/PM 设置为 DE。不知道为什么... <#setting locale="en_US">

于 2011-10-28T10:06:54.927 回答
0

请注意Locale:用于 AM/PM
符号取决于Locale

这会影响解析字符串,如果使用的 AM/PM 字段与预定义的符号不匹配,最终会导致错误。(显然也会影响格式化)

java.time.format.DateTimeFormatter并在创建时java.text.SimpleDateFormat接受一个可选项。Locale如果没有给出。使用系统默认值。


警告:DateTimeFormatter解析时使用 AM/PM 标志的大小写也是相关的,至少对于某些语言环境而言。

例如,印度语言环境要求 AM/PM 标志为小写 ( am, pm),而其他一些语言环境 ( ROOT, ITALY, US, GERMANY) 仅接受大写 AM/PM。

这抛出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"))) 

这导致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")))

使用Locale.USLocale.GERMANYLocale.ROOT结果反转

注意:解析时 AM/PM 的大小写无关紧要SimpleDateFormat (我不推荐使用它,我更喜欢DateTimeFormatter

于 2021-06-15T07:49:43.737 回答