如何使用Java时间库将符合ISO要求的字符串解析为Date

时间:2019-04-05 16:43:49

标签: java java-time datetime-parsing java.util.date

我有各种格式的时间戳,例如:

2018-07-21T00:50:39
2017-11-20T23:18:27.529Z

我需要将它们解析为java.util.Date,并尝试了以下方法,它们都适用于第一种格式,但是第二种格式却失败了。

这是我尝试过的方法,它是错误的:

1。

private Date try3(String dateString) {
        return Date.from(Instant.parse(dateString).atZone(ZoneId.of("UTC")).toInstant());
    }

它在第一种格式失败,错误:

java.time.format.DateTimeParseException: Text '2017-11-20T23:18:28' could not be parsed at index 19

2。

private Date try2(String dateString) {
    return Date.from(LocalDateTime.parse(dateString).atZone(ZoneId.of("UTC")).toInstant());
}

对于第二种格式,此方法抛出错误:

java.time.format.DateTimeParseException: Text '2017-11-20T23:18:27.529Z' could not be parsed, unparsed text found at index 23

3:

private Date try1(String dateString) {
    return Date.from(ZonedDateTime.parse(dateString,
                    DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss").withZone(ZoneId.of("UTC"))).toInstant());

}

对于第二种格式,以上方法将引发错误:

java.time.format.DateTimeParseException: Text '2017-11-20T23:18:27.529Z' could not be parsed, unparsed text found at index 19

我最终得到了 Joda库

private Date try4(String dateString) {
        return new DateTime(dateString).withZone(DateTimeZone.UTC).toDate();
    }

但是在Java时间库中真的有任何方法可以做到这一点吗?

2 个答案:

答案 0 :(得分:1)

java.time

这已经被无数次报道了。因此,搜索堆栈溢出以获取更多信息。

请勿使用DateCalendar。仅使用 java.time 。同样,Joda-Time也被 java.time 取代(两者均由同一个人Stephen Colebourne领导)。

您的字符串输入均为标准ISO 8601格式。 java.time 类在解析/生成字符串时默认使用这些格式。

第一个缺少从UTC或时区偏移的指示符,因此它表示时刻。

LocalDateTime.parse( "2018-07-21T00:50:39" )

Z中的第二个字母,表示UTC,发音为“ Zulu”。

Instant.parse( "2017-11-20T23:18:27.529Z" )

要用一种方法处理两种格式,请在输入字符串中搜索Z的存在并相应地分支。另外,如果收到意外输入,请捕获异常。

如果必须具有java.util.Date对象,请参见旧类的JavaDoc中用于新方法fromto…的类,这些旧类将与 java.time < / em>类。正如我所说,所有这些都已经被涵盖了很多次,因此请搜索更多信息。

答案 1 :(得分:1)

您总是想获得相同的类型,而且我似乎明白,如果字符串中没有偏移量,则需要使用UTC(这一点很重要)。我建议您指定一个带有可选UTC偏移量和默认UTC(零偏移量)的格式化程序,以防字符串中没有任何偏移量。

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
            .appendPattern("[X]")
            .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
            .toFormatter();

    String withoutZ = "2018-07-21T00:50:39";
    Instant anInstant = formatter.parse(withoutZ, Instant::from);
    System.out.println(anInstant);

    String withZ = "2017-11-20T23:18:27.529Z";
    Instant anotherInstant = formatter.parse(withZ, Instant::from);
    System.out.println(anotherInstant);

输出:

2018-07-21T00:50:39Z
2017-11-20T23:18:27.529Z

格式模式字符串[X]中的方括号表示偏移量X是可选的。 ISO_LOCAL_DATE_TIME处理秒上是否存在小数。

我希望您知道Date类的设计很差且过时了,因此通常您不希望一个,而只问一个,因为遗留API必不可少您现在不能更改。在这种情况下,请按照您的问题进行Instant的最终转换。

可变日期/时间格式通常使用的技术包括:

  1. 依次尝试多种已知格式。
  2. 在确定使用哪种格式之前先品尝一下字符串。就您而言,您可能已经按照Basil Bourque的答案中的建议在.endsWith("Z")上分支了。
  3. 格式模式中的可选部分。
  4. DateTimeFormatterBuilder.parseDefaulting()表示解析的字符串中可能不存在的部分。
  5. DateTimeFormatter.parseBest()

如您所见,我在这里使用项目3和4.。