哪些 MIN/MAX 值将同时适用于 ZonedDateTime 和 Instant.toEpochMilli?

2022-09-02 10:04:20

我想使用可以在 和 之间转换的 MIN/MAX 时间值,用作筛选器/查询的哨兵值。ZonedDateTimeInstant.toEpochMilli()

我试过了:

OffsetDateTime.MIN.toInstant().toEpochMilli();
OffsetDateTime.MAX.toInstant().toEpochMilli();

但我得到这个例外:

java.lang.ArithmeticException: long overflow

    at java.lang.Math.multiplyExact(Math.java:892)
    at java.time.Instant.toEpochMilli(Instant.java:1237)

然后我尝试了这个:

ZonedDateTime.ofInstant(Instant.MIN, ZoneId.systemDefault());
ZonedDateTime.ofInstant(Instant.MAX, ZoneId.systemDefault());

但后来我得到了这个例外:

java.time.DateTimeException: Invalid value for Year (valid values -999999999 - 999999999): -1000000001

    at java.time.temporal.ValueRange.checkValidIntValue(ValueRange.java:330)
    at java.time.temporal.ChronoField.checkValidIntValue(ChronoField.java:722)
    at java.time.LocalDate.ofEpochDay(LocalDate.java:341)
    at java.time.LocalDateTime.ofEpochSecond(LocalDateTime.java:422)
    at java.time.ZonedDateTime.create(ZonedDateTime.java:456)
    at java.time.ZonedDateTime.ofInstant(ZonedDateTime.java:409)

我也试过“Z”:ZoneId

ZonedDateTime.ofInstant(Instant.MIN, ZoneId.of("Z"))

但这会返回与上一个相同的异常。

最后,我尝试了以下方法,它似乎有效:

ZonedDateTime.ofInstant(Instant.EPOCH, ZoneId.of("Z"));
ZonedDateTime.ofInstant(Instant.EPOCH.plusMillis(Long.MAX_VALUE), ZoneId.of("Z"));

这是最好的解决方案吗?


答案 1

Instant.EPOCH等价于 ,所以我不确定它是否是最小值的良好候选者(当然,这取决于您的需求 - 如果您的所有日期都在1970年之后,那么就可以了)。1970-01-01T00:00Z

转换和 to 并非始终有效,因为根据偏移量,可以将字段设置为超出边界的值(如您为例中的年份)。Instant.MINInstant.MAXZonedDateTime

如果您想要可以转换为 和 的远距离日期,则不需要使用内置的 MIN/MAX 常量,因为它们使用非常远的日期(从 -1000000000 到 10000000000 等年份),并且此类远日期的等效 epoch milli 值比值的极限大得多(或更低)。ZonedDateTimeInstantlong

当您需要使用并且它返回一个 时,您必须保持在值的限制之间:toEpochMilli()longlong

Instant minInstant = Instant.ofEpochMilli(Long.MIN_VALUE);
Instant maxInstant = Instant.ofEpochMilli(Long.MAX_VALUE);
ZonedDateTime minZonedDateTime = minInstant.atZone(ZoneOffset.UTC);
ZonedDateTime maxZonedDateTime = maxInstant.atZone(ZoneOffset.UTC);

相应的值为:

minInstant=-292275055-05-16T16:47:04.192Z
maxInstant=+292278994-08-17T07:12:55.807Z
minZonedDateTime=-292275055-05-16T16:47:04.192Z
maxZonedDateTime=+292278994-08-17T07:12:55.807Z

以及 epoch milli 的相应值:

System.out.println("minInstant millis=" + minInstant.toEpochMilli());
System.out.println("maxInstant millis=" + maxInstant.toEpochMilli());

最小值峰值毫量=-9223372036854775808
最大峰值微量=9223372036854775807

我使用了一些特定的时区,因为这些日期是过去/将来的,所以几个小时的偏移不会有太大的区别。无论如何,它们都相当于相同的毫微时刻。ZoneOffset.UTC

您还可以将 to using 方法转换为 (例如 )。。InstantOffsetDateTimeatOffsetminInstant.atOffset(ZoneOffset.UTC)


备注

  • 而不是 ,您可以使用常量 。实际上,如果检查,则结果是 。
    甚至也是,所以两者实际上是一回事。ZoneId.of("Z")ZoneOffset.UTCZoneId.of("Z").equals(ZoneOffset.UTC)trueZoneId.of("Z") == ZoneOffset.UTCtrue
  • 根据查询的值,您不需要使用如此极端的日期。例如,您可以将最小值设置为 1900 年,将最大值设置为 2900 年。这完全取决于您的数据集。但是,如果您的数据库可以处理当年的如此大的值,那么使用上述方法就可以了。

答案 2

推荐