如何将 UTC 偏移日期格式字符串解析为由 | 符号分隔的结果日期



我有一个非常奇怪的问题,我试图解析"2019-12-25T17:00:00-05:00"这样它应该给我结果DEC 12 | Thursday | 5:00pm

我通过使用DateTimeFormatterLocalDate尝试了以下代码

DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssz", Locale.US);
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("MM d | E | hh:mm a", Locale.US);
LocalDate date = LocalDate.parse("2019-12-25T17:00:00-05:00", inputFormatter);
String formattedDate = outputFormatter.format(date);
contentTextView.setText(formattedDate);

但它崩溃了DateTimeParseException: Text '2019-12-25T17:00:00-05:00' could not be parsed at index 19

知道为什么它会崩溃以及我的输出是否会呈现预期的结果吗? 谢谢!

您的字符串2019-12-25T17:00:00-05:00表示具有偏移 UTC 偏移量的UTC时区,因此请使用OffsetDateTime解析该字符串

OffsetDateTime odt = OffsetDateTime.parse("2019-12-25T17:00:00-05:00");
System.out.println(odt.format(DateTimeFormatter.ofPattern("MMM d | E | hh:mm a", Locale.US)));

如果要设置特定时区,可以使用atZoneSameInstant传递 eaxmple 的ZoneId

ZoneId zone = ZoneId.of("America/Chicago");
ZonedDateTime zdt = odt.atZoneSameInstant(zone);

一种格式化大写 DEC 和小写 pm 的方法

我只是对@Deadpool的好答案做一个小补充。获取所有大写字母(如小写的DEC和 am/pm)的月份缩写的一种方法是DateTimeFormatterBuilder及其双参数appendText​(TemporalField, Map<Long,String>)方法。

Locale userLocale = Locale.US;
Map<Long, String> monthNames = new HashMap<>();
for (Month m : Month.values()) {
monthNames.put(Long.valueOf(m.getValue()),
m.getDisplayName(TextStyle.SHORT, userLocale).toUpperCase(userLocale));
}
Map<Long, String> amPmNames = new HashMap<>(3);
amPmNames.put(0L, "am");
amPmNames.put(1L, "pm");
DateTimeFormatter outputFormatter = new DateTimeFormatterBuilder()
.appendText(ChronoField.MONTH_OF_YEAR, monthNames)
.appendPattern(" d | E | hh:mm ")
.appendText(ChronoField.AMPM_OF_DAY, amPmNames)
.toFormatter(userLocale);
OffsetDateTime odt = OffsetDateTime.parse("2019-12-25T17:00:00-05:00");
String formattedDate = odt.format(outputFormatter);
System.out.println(formattedDate);

输出:

12 月 25 日 |周三 |05:00 下午

我假设您正在API级别26下为Android编程并使用ThreeTenABP,因此我已经使用ThreeTen Backport在我的桌面Java 7上进行了测试。从 Java 8 和更新的 API 级别,甚至从 Java 9 开始,存在更优雅的方式来填充这两个映射。

您的代码中出了什么问题?

格式模式字符串中排在最后的小写z时区名称匹配。该文档提供了太平洋标准时间和太平洋标准时间的示例。它与-05:00这样的偏移量不匹配。如果您需要一个格式模式字母,请使用xX或大写Z(它们是不同的,并且都有很好的文档记录)。但是,正如死侍的答案中已经显示的那样,在这种情况下,您不需要显式格式化程序,也不需要格式模式字符串。

代码中的另一个问题:您在问题中使用的LocalDate类是没有一天中时间的日期。您可以将字符串解析为LocalDate,但一天中的时间和偏移量会丢失。因此,不能将LocalDate格式设置为包含一天中的时间的字符串。为此,您需要一个名称中包含DateTime的类,例如OffsetDateTime两个答案中使用的类。

链接

DateTimeFormatter文档详细说明了所有可能的格式模式字母。

最新更新