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

时间:2017-07-11 19:40:37

标签: java java-8 java-time

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

我试过了:

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 个答案:

答案 0 :(得分:13)

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

Instant.MINInstant.MAX转换为ZonedDateTime不会一直有效,因为根据偏移量,字段可以设置为超出边界的值(就像年份一样,在你的情况下)。

如果您想要可以转换为ZonedDateTimeInstant的远距离日期,则不需要使用内置的MIN / MAX常量,因为它们使用非常远的日期(来自如年 - 例如-1000000000到1000000000),这些远距离日期的等效 epoch milli 值远大于(或低于)long值的限制。

当您需要使用toEpochMilli()并返回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);

各自的值为:

  

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());
  

minInstant millis = -9223372036854775808
  maxInstant millis = 9223372036854775807

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

您还可以使用Instant方法将OffsetDateTime转换为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。这一切都取决于您的数据集。但是如果您的数据库可以处理一年中的这么大的值,那么使用上面的方法就可以了。