web-dev-qa-db-ja.com

ZonedDateTimeとInstant.toEpochMilliの両方で機能するMIN / MAX値はどれですか?

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

それが最善の解決策ですか?

14
jacob

_Instant.Epoch_は_1970-01-01T00:00Z_と同等であるため、最小値の候補として適切かどうかはわかりません(もちろん、ニーズによって異なります。すべての日付が1970以降の場合は、大丈夫です)。

_Instant.MIN_および_Instant.MAX_からZonedDateTimeへの変換は、オフセットに応じて、フィールドが境界を超えた値に設定される可能性があるため、常に機能しません(たとえば、場合)。

ZonedDateTimeおよびInstantに変換できる遠い日付が必要な場合は、組み込みのMIN/MAX定数を使用する必要はありません。これは、(年から-1000000000〜1000000000など)、および同等のEpochミリこのような遠い日付の値は、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

そして、エポックミリのそれぞれの値:

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

minInstant millis = -9223372036854775808
maxInstant millis = 9223372036854775807

特定のタイムゾーンの代わりに_ZoneOffset.UTC_を使用しました。これらの日付は過去/未来の遠い場所にあるため、数時間のオフセットでは大きな違いはありません。とにかく、それらはすべて同じミリ秒に相当します。

Instantメソッド(minInstant.atOffset(ZoneOffset.UTC)など)を使用して、OffsetDateTimeatOffsetに変換することもできます。


メモ

  • ZoneId.of("Z")の代わりに、定数_ZoneOffset.UTC_を使用できます。実際、ZoneId.of("Z").equals(ZoneOffset.UTC)をチェックすると、結果はtrueになります。
    ZoneId.of("Z") == ZoneOffset.UTCでもtrueでもあるので、どちらも同じものです。
  • クエリの値によっては、このような極端な日付を使用する必要はありません。たとえば、最小値を1900年に、最大値を2900年に設定できます。それはすべてあなたのデータセットに依存します。ただし、データベースがその年のそのような大きな値を処理できる場合は、上記のアプローチを使用しても問題ありません。
16
user7605325