web-dev-qa-db-ja.com

java.util.DateとJava.sql.Date

Java.util.Date vs Java.sql.Date:いつ使うのか、そしてその理由は?

474
flybywire

おめでとうございます、JDBC:Dateクラスの処理が大好きです。

基本的にデータベースは通常少なくともthree形式のdatetimeフィールドをサポートします。これはdate、timeそしてtimestampです。これらはそれぞれJDBCに対応するクラスを持ち、それぞれが Java.util.Date を拡張します。これら3つのそれぞれのクイックセマンティクスは次のとおりです。

  • Java.sql.Date はSQL DATEに対応します。つまり、年、月、日を格納し、時、分、秒、ミリ秒は無視されます。さらにsql.Dateはタイムゾーンに関連付けられていません。
  • Java.sql.Time はSQL TIMEに対応し、明らかなように時、分、秒、ミリ秒についての情報のみを含みます。
  • Java.sql.Timestamp は、カスタマイズ可能な精度でナノ秒(util.Dateはミリ秒だけをサポートします!)までの正確な日付であるSQL TIMESTAMPに対応します。

これら3つの型に関してJDBCドライバを使用するときの最も一般的なバグの1つは、型が誤って処理されることです。これは、sql.Dateはタイムゾーン固有であり、sql.Timeは現在の年、月、日などを含むことを意味します。

最後に:どちらを使うべきですか?

実際には、フィールドのSQL型に依存します。 PreparedStatementには3つの値すべての設定子があり、#setDate()sql.Date#setTime()sql.Time#setTimestamp()sql.Timestampです。

ps.setObject(fieldIndex, utilDateObject);を使用する場合、ほとんどのJDBCドライバに通常のutil.Dateを渡すことができますが、それは正しい型であるかのように喜んでそれを食い物にしますが、後でデータを要求するとき、実際にものが足りないことに気付くでしょう。

私は本当に日付のどれもまったく使うべきではないと言っています。

私が言っていることは、ミリ秒/ナノ秒を普通の長さとして保存し、それらをあなたが使用しているどんなオブジェクトにも変換することです(obligatory joda-time plug)。 1つの手っ取り早い方法は、日付コンポーネントを別の日付コンポーネントとして保存することです。例えば、今は20100221と154536123です。これらのマジックナンバーはSQLクエリで使用でき、データベース間で移植できます。 JDBC/Java Date APIのこの部分を完全に避けることができます。

561
Esko

最後の編集: Java 8以降は、Java.util.DateJava.sql.Dateも使用できない場合は使用しないでください。代わりに(Jodaベースの) Java.time パッケージを使用することをお勧めします。 Java 8を使用していない場合は、これが元の応答です。


Java.sql.Date - それを使用するライブラリのメソッド/コンストラクタを呼び出すとき(JDBCのように)。他にはありません。 JDBCを明示的に扱わないアプリケーション/モジュールのデータベースライブラリに依存関係を導入したくはありません。

Java.util.Date - それを使うライブラリを使うとき。それ以外の場合、いくつかの理由から、可能な限り少なくします。

  • これは変更可能です。つまり、メソッドに渡すたびに、またはメソッドから戻すたびに、防御コピーを作成する必要があります。

  • それは日付をあまりうまく処理しません、それはあなたのもののような人々を本当に逆にします、日付処理クラスがすべきだと思います。

  • さて、j.u.Dはうまく機能しないので、Calendarクラスが導入されました。それらはまた変更可能で、一緒に使うのがひどいので、あなたに選択の余地がなければ避けるべきです。

  • Joda Time API (のようなより良い選択肢があります。これはJava 7にもなり、新しい公式の日付処理APIになるかもしれません。 - クイック検索 はそうではないと言います)。

Jodaのような新しい依存関係を導入するのがやり過ぎだと感じた場合、オブジェクトのタイムスタンプフィールドにlongsを使用するのはそれほど悪いことではありません。

57
gustafc

Java.sql.Dateを使うのはPreparedStatement.setDateの中だけです。それ以外の場合は、Java.util.Dateを使用してください。 ResultSet.getDateJava.sql.Dateを返すと言っていますが、Java.util.Dateに直接代入することができます。

19
Paul Tomblin

私は同じ問題を抱えていました、準備されたステートメントに現在の日付を挿入するために私が見つけた最も簡単な方法はこれです:

preparedStatement.setDate(1, new Java.sql.Date(new Java.util.Date().getTime()));
10
Israelm

JavaのJava.util.Dateクラスは特定の瞬間を表します(例:2013年11月25日16時30分45秒からミリ秒まで)。ただし、DBのDATEデータ型は日付のみを表します(例: 2013年11月25日)。誤ってJava.util.DateオブジェクトをDBに提供しないようにするために、JavaではSQLパラメータを直接Java.util.Dateに設定することはできません。

PreparedStatement st = ...
Java.util.Date d = ...
st.setDate(1, d); //will not work

しかしそれでも、あなたはそれを力/意図によって行うことができます(そして時間と分はDBドライバーによって無視されます)。これはJava.sql.Dateクラスで行われます。

PreparedStatement st = ...
Java.util.Date d = ...
st.setDate(1, new Java.sql.Date(d.getTime())); //will work

Java.sql.Dateオブジェクトは、(Java.util.Dateから構築するのが簡単になるように)瞬間を格納することができますが、時間を要求しようとすると例外をスローします(その概念を強制するため)。日付のみ)。 DBドライバはこのクラスを認識し、時間に0を使用することが期待されています。これを試して:

public static void main(String[] args) {
  Java.util.Date d1 = new Java.util.Date(12345);//ms since 1970 Jan 1 midnight
  Java.sql.Date d2 = new Java.sql.Date(12345);
  System.out.println(d1.getHours());
  System.out.println(d2.getHours());
}
2
Kent Tong