【问题标题】:Unable to parse DateTime-string with AM/PM marker无法使用 AM/PM 标记解析日期时间字符串
【发布时间】:2011-04-06 19:54:15
【问题描述】:

我要格式化的字符串如下所示: 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,但似乎找不到我做错的地方。

有什么建议吗?

【问题讨论】:

  • “a”和“aa”都为我工作。你的 java 版本是多少?

标签: java simpledateformat


【解决方案1】:

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

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

【讨论】:

  • 感谢您指出这一点。说得通,解决了我的问题。
  • 这里的教训是,在进行日期时间工作时,始终指定所需/预期的区域设置和时区。如果省略其中任何一个,则您隐含地依赖 JVM 的当前默认值。额外提示:谷歌“Joda-Time”和“java.time”。
  • 如果异常消息不仅是“无法解析的日期”而且是字符串中失败的位置,那就太好了...
【解决方案2】:

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

【讨论】:

    【解决方案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();
            }
    

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

    【讨论】:

      【解决方案4】:

      现代答案:

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

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

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

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

      【讨论】:

        【解决方案5】:

        java.time

        您可以使用DateTimeFormatterBuilder 构建不区分大小写的解析器。由于日期时间解析/格式化类型(例如DateTimeFormatterSimpleDateFormat 等)是Locale 敏感的,因此您应该始终使用带有此类类型的Locale。我使用了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 了解有关 modern date-time API* 的更多信息。


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

        【讨论】:

          【解决方案6】:

          关于Locale的注释:
          用于 AM/PM 的 符号 取决于 Locale!

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

          java.time.format.DateTimeFormatterjava.text.SimpleDateFormat 在创建时接受可选的 Locale。如果没有给出。使用系统默认的。


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

          例如,印度语言环境要求 AM/PM 标志为小写(ampm),而其他一些语言环境(ROOTITALYUSGERMANY)仅接受大写的 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,结果是反转

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-07-21
            • 2018-12-16
            • 1970-01-01
            • 2018-05-19
            • 1970-01-01
            • 1970-01-01
            • 2017-12-11
            • 1970-01-01
            相关资源
            最近更新 更多