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 代表上午或下午从 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 在这里显示了一个非常令人惊讶的行为。
2001 年 12 月 13 日星期四 08:59:59 CET
08:59? 12 月13?转换为您提供了正确的时间点。当我打印Date 时,它的toString 方法被调用。这反过来使用我的 JVM 的时区设置来生成字符串,因此输出与发生转换的时区完全不同。因此,显然,当 Metlakatla 的 23:59 时,哥本哈根的第二天已经是 08:59(我的时区;输出中的 CET 是中欧时间)。如果我的 JVM 的时区设置也是 America/Metlakatla,那么输出会更符合预期:
2001 年 12 月 12 日星期三 23:59:59 AKST
java.time 更有帮助
您要求SimpleDateFormat 做的是解析一个包含第 11 天和下午的时间的时间。这确实是自相矛盾的,因为 PM 仅在第 12 天的某个小时开始。因此,期望请求中的例外是合理的。带有标准设置的SimpleDateFormat 不会给你这个。 SimpleDateFOrmat 给你一个错误的结果并假装一切都很好,这是非常典型的。但是,让我们用您的格式模式字符串MMM dd yyyy HH:mm:ssa 尝试一下我的现代代码。然后我们得到:
线程“主”java.time.format.DateTimeParseException 中的异常:
无法解析文本“2001 年 12 月 12 日晚上 11:59:59”:发现冲突:
字段 AmPmOfDay 0 与 AmPmOfDay 1 不同,源自 11:59:59
我并没有声称我完全理解为什么会这样措辞,但它提到了 AM/PM 中的冲突,而这正是我们所拥有的。
PS
一开始我并没有想到我会提供答案,但最后我被一方面bohemian’s comment 激怒了,只有 Joop Eggen 的答案是正确的,另一方面是几个comments by Basil Bourque声称您无法使用 Joop Eggen 正在使用的 SimpleDateFormat。所以我想把事情弄清楚。
链接
Oracle tutorial: Date Time 解释如何使用java.time。