threetenbp:解析具有时区名称的日期时出现异常

threetenbp: Parse exception when parsing date with time-zone name

提问人:hildegard 提问时间:5/16/2017 最后编辑:hildegard 更新时间:5/17/2017 访问量:1436

问:

我正在尝试以 EEE 格式解析日期,dd MMM yyyy HH:mm:ss zzz,例如使用 threeten 的 DateTimeFormatter 解析“Tue, 16 May 2017 07:44:48 GMT”等字符串。但是,由于某种原因,似乎无法解析时区名称(我尝试在没有时区名称部分的情况下解析相同的字符串,并且有效)。

下面是代码的解析部分:

DateTimeFormatter parseFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
ZonedDateTime parsedDate = ZonedDateTime.parse(date, parseFormatter);

我收到以下错误:

org.threeten.bp.format.DateTimeParseException: Text '2017 年 5 月 16 日星期二 13:02:16 GMT' 无法在索引 26 处解析

我为时区名称部分尝试了各种不同的格式(例如 z、zzz、Z、ZZZ),但没有任何效果。同样,如果我解析一个没有时区名称部分的子字符串日期(到 LocalDateTime),那么它可以工作,所以我确定问题出在时区名称上。有谁知道问题可能是什么?

java android 解析 datetime threetenbp

评论

0赞 Anonymous 5/17/2017
您的代码与我的 Java 8 配合得很好,并且给出了 .有趣。java.time2017-05-16T13:02:16Z[GMT]
0赞 Anonymous 5/17/2017
您是否尝试过用模式字符串代替?这被记录为“例如'Tue, 3 Jun 2008 11:05:30 GMT'”。所以我认为它应该接受 GMT 作为时区名称。DateTimeFormatter.RFC_1123_DATE_TIME
0赞 Basil Bourque 5/17/2017
您的代码也适用于我,尽管我推荐 Ole V.V. 的答案中的解决方案。

答:

4赞 Anonymous 5/17/2017 #1

我不知道为什么你的代码不起作用。当我在 Java 8 中使用这些类时,它会这样做。所以这只是对可能修复的猜测:java.time

    DateTimeFormatter parseFormatter = DateTimeFormatter.RFC_1123_DATE_TIME;
    ZonedDateTime parsedDate = ZonedDateTime.parse(date, parseFormatter);

您会注意到,这是在同一尖齿处的轻微简化。

DateTimeFormatter.RFC_1123_DATE_TIME记录为

返回 RFC-1123 日期时间格式化程序,例如“Tue, 3 Jun 2008 格林威治标准时间 11:05:30'。

所以我认为它应该接受为时区名称。我应该说它适合您的日期字符串,并且它也适用于我的计算机。我相信这个格式化程序使用星期几和月份的英文缩写,无论在什么地方(或者你可以尝试,但我真的认为没有必要)。GMTDateTimeFormatter.RFC_1123_DATE_TIME.withLocale(Locale.ENGLISH)

也就是说,他们说你应该避免使用三个和四个字母的时区缩写。有些是模棱两可的,有些不是完整的时区,这导致了进一步的模棱两可。虽然 GMT 不是最危险的,但解决您的问题的一个坚如磐石的解决方案是,如果您可以获取带有偏移量的日期字符串,例如 或 ,而不是三个字母的区域名称。+00:00Z

请参阅问题和此答案中的两个示例,在 IdeOne.com 实时运行。两者都成功了。

评论

0赞 hildegard 5/17/2017
RFC-1123 日期时间格式化程序确实解决了这个问题。谢谢!
1赞 Basil Bourque 5/17/2017 #2

TL的;博士

在 macOS(非 Android)上使用 ThreeTen-Backport 1.3.4 项目库时:

  • 不明白你的(解析成功)DateTimeParseException
  • 但是我确实得到了一个与Java 8内置的java.time类中分配的时区不同的时区
    而不是
    2017-05-16T13:02:16Z[Africa/Monrovia]2017-05-16T13:02:16Z[GMT]

Africa/Monrovia区?

我们中的一些人已经看到您的代码工作,显然是使用 Java 8 中内置的 java.time 类。

但是你的问题是关于Java 6和Java 7的这些类的向后移植。因此,我尝试了以下示例,使用该 ThreeTen-Backport 项目库。

package com.example.threetenbp.example;

import org.threeten.bp.*;
import org.threeten.bp.format.*;

import java.util.Locale;

/**
 * By Basil Bourque.
 */
public class App {
    public static void main ( String[] args ) {
        App app = new App ( );
        app.doIt ( );
    }

    private void doIt ( ) {
        String input = "Tue, 16 May 2017 13:02:16 GMT";
        DateTimeFormatter parseFormatter = DateTimeFormatter.ofPattern ( "EEE, dd MMM yyyy HH:mm:ss z" , Locale.ENGLISH );
        ZonedDateTime parsedDate = ZonedDateTime.parse ( input , parseFormatter );

        System.out.println ("parsedDate.toString(): " + parsedDate );
    }

}

在macOS Sierra 10.12.4上使用IntellJ 2017.1.x为Java 8构建和运行时,我得到了一个奇怪的结果。我没有得到我的期望或最后,而是得到了利比里亚的非洲/蒙罗维亚时区。这是有效的,因为与UTC的偏移量确实为零(与UTC / GMT相同)。但这不是我们在 Java 8 类中看到的,正如我们得到的 IdeOne.com 所看到的那样。ZZ[GMT]2017-05-16T13:02:16Z[GMT]

parsedDate.toString(): 2017-05-16T13:02:16Z[非洲/蒙罗维亚]

我没有 Java 6 或 Java 7 的实现可供我使用。但我确实尝试在 IntelliJ 中设置我的构建字节码设置以使用 Java 6。同样的结果。

评论

0赞 Anonymous 5/17/2017
确实很好奇,非常好奇。但正如你所说,它有效,而且并非完全不正确。