什么MIN/MAX值适用于ZonedDateTime和Instant.toEpochMilli?

jac*_*cob 13 java java-8 java-time

我想使用可以在ZonedDateTime和之间进行转换的MIN/MAX时间值Instant.toEpochMilli(),以用作过滤器/查询的标记值.

我试过了:

OffsetDateTime.MIN.toInstant().toEpochMilli();
OffsetDateTime.MAX.toInstant().toEpochMilli();
Run Code Online (Sandbox Code Playgroud)

但我得到这个例外:

java.lang.ArithmeticException: long overflow

    at java.lang.Math.multiplyExact(Math.java:892)
    at java.time.Instant.toEpochMilli(Instant.java:1237)
Run Code Online (Sandbox Code Playgroud)

然后我尝试了这个:

ZonedDateTime.ofInstant(Instant.MIN, ZoneId.systemDefault());
ZonedDateTime.ofInstant(Instant.MAX, ZoneId.systemDefault());
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

我也试过'Z' ZoneId:

ZonedDateTime.ofInstant(Instant.MIN, ZoneId.of("Z"))
Run Code Online (Sandbox Code Playgroud)

但是返回与最后一个相同的异常.

最后我尝试了以下,它似乎工作:

ZonedDateTime.ofInstant(Instant.EPOCH, ZoneId.of("Z"));
ZonedDateTime.ofInstant(Instant.EPOCH.plusMillis(Long.MAX_VALUE), ZoneId.of("Z"));
Run Code Online (Sandbox Code Playgroud)

这是最好的解决方案吗?

小智 13

Instant.EPOCH相当于1970-01-01T00:00Z,所以我不确定它是否是最小值的好候选者(当然,这取决于你的需求 - 如果所有日期都在1970年以后,那就没关系了).

转换Instant.MINInstant.MAXZonedDateTime不起作用,因为根据偏移,字段可以设置为值超出界限(如发生与年,你的情况)的所有时光.

如果你想遥远的日期可以转换为ZonedDateTimeInstant,你并不需要使用内置的MIN/MAX常数,因为它们使用很远的日期(从几年如-1000000000到1000000000),和等效时代毫这些远日期的值远远大于(或低于)long值的限制.

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

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);
Run Code Online (Sandbox Code Playgroud)

各自的值是:

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());
Run Code Online (Sandbox Code Playgroud)

minInstant millis = -9223372036854775808
maxInstant millis = 9223372036854775807

我使用的ZoneOffset.UTC不是某个特定的时区,因为这些日期是过去/未来的迄今为止,几个小时的偏移量不会产生太大的影响.无论如何,它们都将相同于毫秒.

您还可以将转换InstantOffsetDateTime使用atOffset方法(例如minInstant.atOffset(ZoneOffset.UTC)).


备注:

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