What MIN/MAX values will work with both ZonedDateTime and Instant.toEpochMilli?

jacob :

I want to use MIN/MAX time values that can convert between ZonedDateTime and Instant.toEpochMilli(), to be used as sentinel values for a filter/query.

I tried:

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

but I get this exception:

java.lang.ArithmeticException: long overflow

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

And then I tried this:

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

but then I get this exception:

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)

I also tried 'Z' ZoneId:

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

but that returns the same exception as the last one.

Finally I tried the following, and it seems to work:

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

Is that the best solution?

user7605325 :

Instant.EPOCH is equivalent to 1970-01-01T00:00Z, so I'm not sure if it's a good candidate for a minimum value (it depends on your needs, of course - if all your dates are after 1970, then it would be fine).

Converting Instant.MIN and Instant.MAX to ZonedDateTime doesn't work all the time because depending on the offset, the fields can be set to values beyond boundaries (like happened with the year, in your case).

If you want far distant dates that can be converted to ZonedDateTime and Instant, you don't need to use the built-in MIN/MAX constants, because they use very far dates (from years like -1000000000 to 1000000000), and the equivalent epoch milli values for such far dates are much greater (or lower) than the limits of a long value.

As you need to use toEpochMilli() and it returns a long, you must stay between the limits of a long value:

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

The respective values are:

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

And the respective values for epoch milli:

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

minInstant millis=-9223372036854775808
maxInstant millis=9223372036854775807

I used ZoneOffset.UTC instead of some specific timezone, because those dates are so far in the past/future, that a few hours offset won't make much difference. And they would all be equivalent to the same millis instant anyway.

You could also convert the Instant to OffsetDateTime using atOffset method (such as minInstant.atOffset(ZoneOffset.UTC)).


Notes:

  • instead of ZoneId.of("Z"), you can use the constant ZoneOffset.UTC. Actually, if you check ZoneId.of("Z").equals(ZoneOffset.UTC), the result is true.
    Even ZoneId.of("Z") == ZoneOffset.UTC is also true, so both are really the same thing.
  • depending on the values of your query, you don't need to use such extreme far dates. You could set the minimum to year 1900 and the maximum to 2900, for example. It all depends on your dataset. But using the approach above will be fine, if your database can handle such big values for the year.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=432441&siteId=1