将 Instant 转换为 OffsetDateTime,然后 OffsetDateTime 上的 Instant.parse() 导致零秒情况下的 DateTimeParseException
Convert Instant to OffsetDateTime then Instant.parse() on the OffsetDateTime leads to DateTimeParseException for zero seconds cases
我正在接收来自服务的即时信息,以下是案例。
在第一种情况下,说 instant = "2021-03-23T04:17:35Z"
& 在第二种情况下,
instant = "2021-07-15T05:27:00Z"
然后需要将 instant 转换为 offsetDateTime,就像
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.UTC)
现在我想计算上面的 offsetDateTime 和 instant.now
之间的小时差
ChronoUnit.HOURS.between(Instant.parse(offsetDateTime), Instant.now())
结果
case 1 : it works fine
case 2 : ERROR : DateTimeParseException: Text '2021-07-15T05:27Z' could not be parsed at index 16
找到原因了:
在情况 2 中,如果它会通过相同的 2021-07-15T05:27:00Z
。它会起作用,但因为 instant.atOffset(ZoneOffset.UTC)
内部会调用下面的方法, 其中零将被删除 ,基本上微小的部分将被整理出来.所以在 fn 下面将 return 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);
}
我假设的一个解决方案是手动附加零,但这可能不是好的做法。
你不需要任何 DateTimeFormatter
您不需要任何 DateTimeFormatter
来解析您的日期时间字符串。现代日期时间 API 基于 ISO 8601 并且不需要明确使用 DateTimeFormatter
对象,只要日期时间字符串符合 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));
}
}
输出:
2021-03-23T04:17:35Z
2021-07-15T05:27:00Z
2737
了解有关现代日期时间 API 的更多信息
正确。
另外,我们再来看题目中的这段代码:
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);
}
首先,如果你想对一个时刻应用偏移量,则不需要LocalDateTime
class。只需这样做:
OffsetDateTime odt = instant.atOffset( myZoneOffset ) ;
请参阅 tutorial on naming conventions at…
、from…
、with…
等
当你想感知某个时刻认为是特定地区人们使用的挂钟时间时,将时区 (ZoneId
) 应用于 Instant
以获得 ZonedDateTime
。使用 ZonedDateTime
而不是 OffsetDateTime
。 ZonedDateTime
比单纯的 OffsetDateTime
更可取,因为它包含更多信息。如果添加或减去移动到另一个时刻,此信息可能是关键的。此信息在生成表示此日期时间对象内容的文本时也很有用。
了解与 UTC 的偏移量只是小时数-分钟-秒数。时区要多得多。时区是政治家决定的特定地区人民使用的偏移量的过去、现在和未来变化的历史。
ZonedDateTime zdt = instant.atZone( myZoneId ) ;
所以你的方法应该是这样的。
public static ZonedDateTime ofInstant(Instant instant, ZoneId zone)
{
ZonedDateTime zdt =
Objects.requireNonNull( instant )
.atZone(
Objects.requireNonNull( zone )
)
;
return zdt ;
}
如果您确实需要 OffsetDateTime
,尽管 ZonedDateTime
是首选,请提取一个。
OffsetDateTime odt = zdt.toOffsetDateTime() ;
我正在接收来自服务的即时信息,以下是案例。
在第一种情况下,说 instant = "2021-03-23T04:17:35Z"
& 在第二种情况下,
instant = "2021-07-15T05:27:00Z"
然后需要将 instant 转换为 offsetDateTime,就像
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.UTC)
现在我想计算上面的 offsetDateTime 和 instant.now
之间的小时差ChronoUnit.HOURS.between(Instant.parse(offsetDateTime), Instant.now())
结果
case 1 : it works fine
case 2 : ERROR :
DateTimeParseException: Text '2021-07-15T05:27Z' could not be parsed at index 16
找到原因了:
在情况 2 中,如果它会通过相同的 2021-07-15T05:27:00Z
。它会起作用,但因为 instant.atOffset(ZoneOffset.UTC)
内部会调用下面的方法, 其中零将被删除 ,基本上微小的部分将被整理出来.所以在 fn 下面将 return 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);
}
我假设的一个解决方案是手动附加零,但这可能不是好的做法。
你不需要任何 DateTimeFormatter
您不需要任何 DateTimeFormatter
来解析您的日期时间字符串。现代日期时间 API 基于 ISO 8601 并且不需要明确使用 DateTimeFormatter
对象,只要日期时间字符串符合 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));
}
}
输出:
2021-03-23T04:17:35Z
2021-07-15T05:27:00Z
2737
了解有关现代日期时间 API 的更多信息
另外,我们再来看题目中的这段代码:
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);
}
首先,如果你想对一个时刻应用偏移量,则不需要LocalDateTime
class。只需这样做:
OffsetDateTime odt = instant.atOffset( myZoneOffset ) ;
请参阅 tutorial on naming conventions at…
、from…
、with…
等
当你想感知某个时刻认为是特定地区人们使用的挂钟时间时,将时区 (ZoneId
) 应用于 Instant
以获得 ZonedDateTime
。使用 ZonedDateTime
而不是 OffsetDateTime
。 ZonedDateTime
比单纯的 OffsetDateTime
更可取,因为它包含更多信息。如果添加或减去移动到另一个时刻,此信息可能是关键的。此信息在生成表示此日期时间对象内容的文本时也很有用。
了解与 UTC 的偏移量只是小时数-分钟-秒数。时区要多得多。时区是政治家决定的特定地区人民使用的偏移量的过去、现在和未来变化的历史。
ZonedDateTime zdt = instant.atZone( myZoneId ) ;
所以你的方法应该是这样的。
public static ZonedDateTime ofInstant(Instant instant, ZoneId zone)
{
ZonedDateTime zdt =
Objects.requireNonNull( instant )
.atZone(
Objects.requireNonNull( zone )
)
;
return zdt ;
}
如果您确实需要 OffsetDateTime
,尽管 ZonedDateTime
是首选,请提取一个。
OffsetDateTime odt = zdt.toOffsetDateTime() ;