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

3

我有一个非常特别的问题,我正在尝试解析"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

有什么想法为什么会崩溃以及我的输出是否会呈现预期的结果? 谢谢!


尝试使用这个格式 "yyyy-MM-dd'T'HH:mm'Z'" DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm'Z'", Locale.US) - Rofie Sagara
由于这个更改,我遇到了崩溃:DateTimeParseException: 在索引16处无法解析文本“2019-12-25T17:00:00-05:00”。 - user11455292
这个怎么样 "yyyy-MM-dd'T'HH:mm:ss:SSSXXX" 或者 "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"? - Rofie Sagara
同样的问题:DateTimeParseException: 无法解析文本“2019-12-25T17:00:00-05:00”,索引为19。 - user11455292
1
我在想这个问题的关闭投票,这真的不清楚吗? - Ryuzaki L
2个回答

7

您的字符串 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方法,并传递ZoneId作为参数,例如:

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

这似乎是有效的,但我得到的结果是:112 25 | 星期三 | 下午05:00,而不是月份Dec,MM是正确的格式吗? - user11455292
太棒了,只有一个问题,有没有一种方法可以将 AM | PM 转换为小写的 am | pm,而不使用 replace 函数? - user11455292
我在这里只看到大写字母 https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html,这是个问题吗?@AngelaHeely - Ryuzaki L
1
好链接,@Deadpool。特别是这个答案。 - Ole V.V.
你了解这个问题吗?:https://stackoverflow.com/questions/57695243/how-do-i-set-timezone-on-a-specific-date?noredirect=1#comment101834800_57695243 - user11455292
显示剩余2条评论

3

格式化大写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,因此我在我的桌面Java 7上进行了测试,使用了ThreeTen Backport。从Java 8及更新的API级别开始,甚至更多地从Java 9开始存在更优雅的方法来填充这两个映射。

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

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

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

链接

DateTimeFormatter 文档列出所有可能的格式模式字母。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接