Java - 在几秒钟内使用AM / PM解析日期(无空格)

时间:2018-06-14 13:46:47

标签: java date parsing

我正在尝试解析以下类型的日期:Dec 12 2001 11:59:59PM

如果AM / PM不在秒的旁边,我将使用以下模式:MMM dd yyyy HH:mm:ss a

然而,使用模式MMM dd yyyy HH:mm:ssa忽略AM / PM(因此始终将其解释为AM)。

我正在尝试使用SimpleDateFormat。我试图指定一个区域设置无济于事。

这可能是使用SimpleDateFormat还是我需要使用替代方法/外部处理? SimpleDateFormat由于在@JsonFormat注释的模式属性中的使用而特别感兴趣。

感谢。

5 个答案:

答案 0 :(得分:4)

我想使用Java8 +中的java.time API而不是旧日期:

String date = LocalDateTime.now().format(
        DateTimeFormatter.ofPattern("MMM dd yyyy hh:mm:ssa", Locale.ENGLISH)
);

或:

DateTimeFormatter format = DateTimeFormatter.ofPattern(
        "MMM dd yyyy hh:mm:ssa", Locale.ENGLISH
);
String date = LocalDateTime.of(2001, Month.DECEMBER, 12, 11, 59, 59).format(format);

<强>输出

Jun 14 2018 03:01:02PM
Dec 12 2001 11:59:59AM

答案 1 :(得分:2)

使用AM / PM您需要12小时hh而不是24小时HH

hh:mm:ss''a

由于k/K/h/H影响a,现在一切都可以与ssa一起使用。

如果ssa仍有问题(似乎是一个错误),请尝试用空文字字符串(单引号)分隔字母。

以下作品:

hh:mm:ssa

答案 2 :(得分:2)

使用SimpleDateFormat可能很有可能,但您可能更愿意使用现代Java日期和时间API java.time

    DateTimeFormatter formatter
            = DateTimeFormatter.ofPattern("MMM dd uuuu hh:mm:ssa", Locale.ENGLISH);
    String dateTimeString = "Dec 12 2001 11:59:59PM";
    LocalDateTime dateTime = LocalDateTime.parse(dateTimeString, formatter);
    System.out.println(dateTime);

输出:

  

2001-12-12T23:59:59

正如其他人所说,你的问题不在于秒与AM / PM标记之间缺少空间,而是在小时内使用大写HH。大写HH表示从00到23的一天中的小时,其中您想要的是小时hh小时内AM或PM从01到12小时。

正如其他人所说,使用SimpleDateFormat及其朋友Date时存在问题:

  • 这些课程已经过时了。
  • 这些课程的设计很差,SimpleDateFormat尤其以麻烦而闻名。您的经历很典型,当然也不少见。
  • SimpleDateFormat获取正确的结果要求JVM时区设置与字符串中理解的时区一致,或者将SimpleDateFormat的时区设置为相关时区。前者很难保证,因为时区设置可以随时从程序的其他部分或在同一JVM中运行的其他程序进行更改。

这也意味着如果您确实需要过时的Date类的实例(例如,对于您不想立即更改的旧API),则需要确定时区转换。然后转换为例如:

    Instant inst = dateTime.atZone(ZoneId.of("America/Metlakatla")).toInstant();
    Date oldfashionedDate = Date.from(inst);
    System.out.println(oldfashionedDate);

我毫不犹豫地向您展示输出,因为Date在这里显示了一个非常令人惊讶的行为。

  

Thu Dec 13 08:59:59 CET 2001

8时59分? 12月 13 ?转换为您提供了正确的时间点。当我打印Date时,会调用其toString方法。这反过来使用我的JVM的时区设置来生成字符串,因此输出与转换发生的时区完全不同。很明显,当它在Metlakatla的23:59时,它已经是哥本哈根第二天的08:59(我的时区;输出中的CET是中欧时间)。如果我的JVM的时区设置也是America / Metlakatla,那么输出会与预期达成一致:

  

Wed Dec 12 23:59:59 AKST 2001

java.time更有帮助

您要求SimpleDateFormat做的是解析第11天和下午1点的时间。这实际上是自相矛盾的,因为PM仅在第12天的小时开始。因此,期望来自请求的异常是合理的。标准设置的SimpleDateFormat并不能满足您的要求。 SimpleDateFOrmat非常典型地给你一个错误的结果并假装一切都很好。但是,让我们暂时尝试使用格式模式字符串MMM dd yyyy HH:mm:ssa的现代代码。然后我们得到:

  

线程“main”中的异常java.time.format.DateTimeParseException:   文本'Dec 12 2001 11:59:59 PM'无法解析:发现冲突:   Field AmPmOfDay 0与源自11:59:59的AmPmOfDay 1不同

我并不是说我完全明白为什么会这样说,但它提到了AM / PM中的冲突,这正是我们所拥有的。

PS

我一开始并没有想过我会给出一个答案,但最后我一方面被bohemian’s comment挑起,只有Joop Eggen的回答是正确的,另一方面是几个{ {3}}声称您无法使用Joop Eggen正在使用的SimpleDateFormat。所以我想把事情做好。

链接

comments by Basil Bourque解释如何使用java.time

答案 3 :(得分:1)

Java内部使用构建器模式。这稍微修改了DateTimeFormatter.RFC_1123_DATE_TIME的源代码:

我建议不要使用替代方法DateTimeFormatter.ofPattern(),但在某些可能遇到ofPattern限制的情况下,它可以证明更强大。

    Map<Long, String> moy = new HashMap<>();
    moy.put(1L, "Jan"); moy.put(2L, "Feb"); moy.put(3L, "Mar");
    moy.put(4L, "Apr"); moy.put(5L, "May"); moy.put(6L, "Jun");
    moy.put(7L, "Jul"); moy.put(8L, "Aug"); moy.put(9L, "Sep");
    moy.put(10L, "Oct"); moy.put(11L, "Nov"); moy.put(12L, "Dec");
    DateTimeFormatter format = new DateTimeFormatterBuilder()
            .appendText(MONTH_OF_YEAR, moy)
            .appendLiteral(' ')
            .appendValue(DAY_OF_MONTH, 2)
            .appendLiteral(' ')
            .appendValue(YEAR, 4, 4, EXCEEDS_PAD)
            .appendLiteral(' ')
            .appendValue(HOUR_OF_AMPM, 1, 2, NOT_NEGATIVE)
            .appendLiteral(':')
            .appendValue(MINUTE_OF_HOUR, 1, 2, NOT_NEGATIVE)
            .optionalStart()
            .appendLiteral(':')
            .appendValue(SECOND_OF_MINUTE, 1, 2, NOT_NEGATIVE)
            .optionalEnd()
            .appendText(AMPM_OF_DAY)
            .toFormatter();

    System.out.println(format.parse("Jun 14 2018 2:51:22AM")); // {},ISO resolved to 2018-06-14T02:51:22
    System.out.println(format.parse("Jun 14 2018 2:51:22PM")); // {},ISO resolved to 2018-06-14T14:51:22

答案 4 :(得分:0)

注意

不幸的是,以下代码不准确。永远不会读取AM / PM标记。根据当地时间,假设是AM或PM。

原始答案

使用以下格式字符串“MMM dd yyyy HH:mm:ssaaa”。

String str = "Jun 14 2018 13:53:19PM";
DateFormat df = new SimpleDateFormat("MMM dd yyyy HH:mm:ssaaa");
try {
  Date date = df.parse(str);
  System.out.print(df.format(date));
} catch (ParseException e) {
  e.printStackTrace();
}