web-dev-qa-db-ja.com

UnsupportedOperationException-Java.sql.DateでtoInstant()を呼び出せないのはなぜですか?

_Java.util.Date_クラスには、Dateインスタンスを_Java.time.Instant_に変換するtoInstant()というメソッドがあります。

_Java.sql.Date_クラスは_Java.util.Date_クラスを拡張しますが、_Java.sql.Date_でtoInstant()を呼び出そうとすると、UnsupportedOperationExceptionを受け取ります。

なぜtoInstant()は_Java.sql.Date_でサポートされていない操作ですか?

_Java.sql.Date_を_Java.time.Instant_に変換する「正しい」方法は何ですか?

42
Andrew Mairose

JavaDoc を確認してください

sql.Dateには時間コンポーネントがないため、それをtime.Instantに変換する可能性はありません

このメソッドは常にUnsupportedOperationExceptionをスローします。SQLDate値には時刻コンポーネントがないため、使用しないでください。

23
Yassin Hajaj

Java.sql.DateJava.time間の正しいマッピングはLocalDateです:

LocalDate date = sqlDate.toLocalDate();

本当に必要な場合を使用すると、Instantを導出できますが、追加情報(時間)は任意です。例えば:

Instant i = date.atStartOfDay(ZoneOffset.UTC).toInstant();
34
assylias

Java.sql.Dateには、日付コンポーネント(日付、月、および年)のみが含まれます。日付と時刻の両方のコンポーネントはありません。 toInstantはDate/Timeコンポーネントの両方を必要とするため、Java.sql.DateインスタンスのtoInstantはUnsupportedOperationException例外をスローします。

Java.util.Date OR Java.sql.Timestampには両方の日付/時刻コンポーネントがあるため、toInstant()が機能します!

このようにすることができます:

// Time is 00:00:00.000

new Java.util.Date(sqlDate.getTime()).toInstant() 

更新:

Instant.ofEpochMilli(sqlDate.getTime());

// OR
new Java.util.Date(sqlDate.getTime()).toInstant();

ToInstant()がInstant.ofEpochMilli(getTime())を内部的に呼び出すため、同じ結果が返されます。

public Instant toInstant() {
    return Instant.ofEpochMilli(getTime());
}
22
Loc

これまでの回答は、_Java.sql.Date_に時間情報がないという詳細に集中しています。それは正しいですが、このタイプがInstantへの直接変換を提供できない本当の理由または十分な理由ではありません。残念ながら Java-8のドキュメント は同じ間違いをして、ユーザーに問題が時間情報が欠けているだけだと思わせるようにします。

概念的には、タイプ_Java.sql.Date_はローカルタイプを表します。世界中のどの地域でも異なるカレンダー日付をモデル化しています。しかし、Instantは世界中の地球上で同じです。 ユーザーは変換を行うためにタイムゾーンまたはタイムゾーンオフセットが必要です。

悲劇的なことに、タイプ_Java.sql.Date_は、グローバル型(インスタントのような)である_Java.util.Date_を継承します。ただし、この継承は実際には実装の継承を示しており、型の継承を示しているわけではありません。これらの古いJDBCクラスの設計が壊れていると考えるもう1つの理由。したがって、ハックを使用して、メソッドgetTime()を介して_Java.sql.Date_のインスタンス内で_Java.util.Date_をラップし、最終的にインスタントへの直接変換を可能にすることができます。ただし、この変換では、システムのデフォルトのタイムゾーンが暗黙的に使用されます。

それでは、どのように正しく学問的な方法で変換するのでしょうか?ここで正しい方向を指している Java-8のドキュメント について考えてみましょう。

_Java.sql.Date sqlDate = ...;
LocalDate calendarDate = sqlDate.toLocalDate();
ZonedDateTime zdt = calendarDate.atStartOfDay(ZoneId.of("Europe/Paris"));
Instant instant = zdt.toInstant();
_
14
Meno Hochschild