Какие значения MIN / MAX будут работать как с ZonedDateTime, так и с Instant.toEpochMilli?

Я хочу использовать минимальные / максимальные значения времени, которые могут преобразовываться между ZonedDateTime и Instant.toEpochMilli(), для использования в качестве значений sentinel для фильтра / запроса.

пробовал:

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-01-01T00:00Z, поэтому я не уверен, что это хороший кандидат на минимальное значение (это зависит от ваших потребностей, конечно - если все ваши даты после 1970 года, тогда все будет хорошо).

преобразование Instant.MIN и Instant.MAX to ZonedDateTime не работает все время, потому что в зависимости от смещения поля могут быть установлены на значения за пределами границ (как это произошло с годом, в вашем случае).

если вы хотите далекие даты, которые могут быть преобразованы в ZonedDateTime и Instant, вам не нужно использовать встроенные константы MIN / MAX, потому что они используют очень далекие даты (от лет, таких как -1000000000 до 1000000000), и эквивалент эпоха Милли значения для таких далеких дат намного больше (или ниже), чем пределы a 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.192 Z
maxInstant=+292278994-08-17T07:12: 55.807 Z
minZonedDateTime=-292275055-05- 16T16: 47: 04.192 Z
maxZonedDateTime=+292278994-08-17T07:12: 55.807 Z

и соответствующие значения для 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 to 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, например. Все зависит от вашего набора данных. Но, используя этот подход, будет хорошо, если ваша база данных может обрабатывать такие большие значения за год.