将 Instant 转换为 OffsetDateTime,然后 OffsetDateTime 上的 Instant.parse() 会导致零秒情况下的 DateTimeParseException

Lok*_*h_K 6 java java-8 java-time

我从服务中收到即时消息,以下是案例。

在第一种情况下,说instant = "2021-03-23T04:17:35Z"& 在第二种情况下, instant = "2021-07-15T05:27:00Z"

然后需要将 instant 转换为 offsetDateTime,就像

OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.UTC)
Run Code Online (Sandbox Code Playgroud)

现在我想计算上面的 offsetDateTime 和 instant.now 之间的小时差距

ChronoUnit.HOURS.between(Instant.parse(offsetDateTime), Instant.now())
Run Code Online (Sandbox Code Playgroud)

结果

情况1:工作正常

情况 2:错误:DateTimeParseException: Text '2021-07-15T05:27Z' could not be parsed at index 16

想通了原因: 在情况2中,如果它也能通过的话也是一样的2021-07-15T05:27:00Z。它会起作用,但在instant.atOffset(ZoneOffset.UTC)内部会调用下面的方法,其中零将被删除,基本上分钟部分将被整理出来。所以下面的 fn 将返回2021-07-15T05:27Z,这将导致 DateTimeParseException。

public static OffsetDateTime ofInstant(Instant instant, ZoneId zone) {
        Objects.requireNonNull(instant, "instant");
        Objects.requireNonNull(zone, "zone");
        ZoneRules rules = zone.getRules();
        ZoneOffset offset = rules.getOffset(instant);
        LocalDateTime ldt = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset);
        return new OffsetDateTime(ldt, offset);
    }
Run Code Online (Sandbox Code Playgroud)

我假设手动附加零的一种解决方案,但这可能不是一个好的做法。

Bas*_*que 6

Avinash 的答案是正确的。

\n

另外,让\xe2\x80\x99s看看问题中的这段代码:

\n
public static OffsetDateTime ofInstant(Instant instant, ZoneId zone) \n{\n        Objects.requireNonNull(instant, "instant");\n        Objects.requireNonNull(zone, "zone");\n   \n        ZoneRules rules = zone.getRules();\n        ZoneOffset offset = rules.getOffset(instant);\n        LocalDateTime ldt = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset);\n\n        return new OffsetDateTime(ldt, offset);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

首先,如果你想对某个时刻应用偏移量,则不需要LocalDateTime类。只需这样做:

\n
OffsetDateTime odt = instant.atOffset( myZoneOffset ) ;\n
Run Code Online (Sandbox Code Playgroud)\n

请参阅有关、、等命名约定的教程。at\xe2\x80\xa6from\xe2\x80\xa6with\xe2\x80\xa6

\n

当您想要了解特定地区的人们使用的挂钟时间时,请将时区 ( ZoneId) 应用于 以Instant获得ZonedDateTime。使用ZonedDateTime而不是OffsetDateTime. AZonedDateTime比单纯的更可取,OffsetDateTime因为它包含更多信息。如果通过添加或减去来移动到另一个时刻,此信息可能很重要。在生成表示此日期时间对象内容的文本时,此信息也很有用。

\n

了解与 UTC 的偏移量只是小时、分钟、秒的数量。时区的意义要大得多。时区是政治家决定的特定地区人民使用的偏移量的过去、现在和未来变化的历史。

\n
ZonedDateTime zdt = instant.atZone( myZoneId ) ;\n
Run Code Online (Sandbox Code Playgroud)\n

所以你的方法应该是这样的。

\n
public static ZonedDateTime ofInstant(Instant instant, ZoneId zone) \n{\n    ZonedDateTime zdt = \n        Objects.requireNonNull( instant )\n        .atZone(\n            Objects.requireNonNull( zone )\n        )\n    ;\n    return zdt ;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

如果您确实需要一个OffsetDateTime,尽管ZonedDateTime是首选,但请提取一个。

\n
OffsetDateTime odt = zdt.toOffsetDateTime() ;\n
Run Code Online (Sandbox Code Playgroud)\n


Arv*_*ash 5

你不需要任何DateTimeFormatter

您不需要任何内容DateTimeFormatter​​来解析日期时间字符串。现代日期时间 API 基于ISO 8601DateTimeFormatter ,只要日期时间字符串符合 ISO 8601 标准,就不需要显式使用对象。

import java.time.Instant;
import java.time.temporal.ChronoUnit;

public class Main {
    public static void main(String[] args) {
        Instant instant1 = Instant.parse("2021-03-23T04:17:35Z");
        Instant instant2 = Instant.parse("2021-07-15T05:27:00Z");

        System.out.println(instant1);
        System.out.println(instant2);

        System.out.println(ChronoUnit.HOURS.between(instant1, instant2));
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

2021-03-23T04:17:35Z
2021-07-15T05:27:00Z
2737
Run Code Online (Sandbox Code Playgroud)

ONLINE DEMO

从Trail: Date Time中了解有关现代日期时间 API 的更多信息。

  • @toxi_code - 不,不要那样做。如果由于某种原因,您需要将“offsetDateTime”转换为“Instant”,只需将其作为“offsetDateTime.toInstant()”即可,即您应该将其作为“ChronoUnit.HOURS. Between(offsetDateTime.toInstant(), Instant”)。现在())`。为此,不需要使用“DateTimeFormatter”,这不仅没有必要,而且容易出错。 (5认同)