回答:
おめでとうございます。JDBC:日付クラスの処理で私のお気に入りのペットピートをヒットしました。
基本的に、データベースは通常、日付、時刻、タイムスタンプの少なくとも3つの形式の日時フィールドをサポートしています。これらのそれぞれに対応するJDBCのクラスがあり、それぞれが拡張されjava.util.Date
ます。これら3つそれぞれのクイックセマンティクスは次のとおりです。
java.sql.Date
SQL DATEに対応します。これは、年、月、日を格納し、時、分、秒、ミリ秒は無視されることを意味します。さらにsql.Date
、タイムゾーンに関連付けられていません。java.sql.Time
SQL TIMEに対応し、明らかなように、時間、分、秒、ミリ秒に関する情報のみが含まれます。java.sql.Timestamp
カスタマイズ可能な精度でナノ秒の正確な日付であるSQL TIMESTAMPに対応します(ミリ秒のみをサポートすることに注意してくださいutil.Date
!)。これらの3つのタイプに関連してJDBCドライバーを使用する場合の最も一般的なバグの1つは、タイプが正しく処理されないことです。これsql.Date
はタイムゾーン固有であり、sql.Time
現在の年、月、日などが含まれていることを意味します。
実際には、フィールドのSQLタイプに依存します。PreparedStatement
、すべての3つの値のセッターを持つ#setDate()
ための一つであるsql.Date
、#setTime()
のためにsql.Time
と#setTimestamp()
のためにsql.Timestamp
。
使用するps.setObject(fieldIndex, utilDateObject);
場合、実際util.Date
にほとんどのJDBCドライバーに通常のタイプを与えることができることに注意してください。これは、正しいタイプであるかのように喜んでそれを食い尽くしますが、後でデータを要求すると、実際に欠落していることに気付く場合があります。
私が言っていることは、ミリ秒/ナノ秒をプレーンロングとして保存し、使用しているオブジェクトに変換することです(必須のjoda-timeプラグイン)。実行できる1つのハックな方法は、日付コンポーネントを別の長い時間コンポーネントとして格納することです。たとえば、現在のところ、20100221と154536123になります。これらのマジックナンバーはSQLクエリで使用でき、データベースから別のコンポーネントに移植できます。 JDBC / Java Date APIのこの部分を完全に回避できます。
後期編集: Java 8 以降では、回避することも回避することjava.util.Date
もjava.sql.Date
できず 、代わりにjava.time
(Jodaに基づく)パッケージを使用することをお勧めします。Java 8を使用していない場合、元の応答は次のとおりです。
java.sql.Date
-(JDBCのような)それを使用するライブラリのメソッド/コンストラクタを呼び出すとき。そうでなければ。JDBCを明示的に処理しないアプリケーション/モジュールのデータベースライブラリに依存関係を導入したくない場合。
java.util.Date
-それを使用するライブラリを使用する場合。それ以外の場合は、いくつかの理由により、可能な限り少なくします。
これは変更可能です。つまり、メソッドに渡すか、メソッドから返すたびに、防御的なコピーを作成する必要があります。
それは日付をあまりうまく処理しません。あなたのような人々を本当に後退させます。
今、juDはうまく機能しないため、恐ろしいCalendar
クラスが導入されました。また、それらは変更可能であり、操作がひどいため、選択の余地がない場合は回避する必要があります。
Joda Time API(Java 7になり、新しい公式の日付処理APIになる可能性もあります - クイック検索ではそうはなりません)など、より優れた代替手段があります。
long
Jodaのような新しい依存関係を導入するのはやり過ぎだと感じる場合は、オブジェクトのタイムスタンプフィールドにsを使用するのはそれほど悪いことではありませんが、私自身は通常、タイプセーフとドキュメント化のために、それらを渡すときにjuDでラップします。
java.sql.Date
とPreparedStatement
など!あなたはしているが、それを周りに渡す場合でも、使用LocalDate
、使用して変換しているjava.sql.Date.valueOf
とjava.sql.Date.valueOf
、それを設定するとき、および使用可能な限り早期に戻ってそれを変換するjava.sql.Date.toLocalDate
あなたはできるだけのjava.sqlが関与したいので、それが可変なので、再び- 。
使用するのjava.sql.Date
はPreparedStatement.setDate
。それ以外の場合は、を使用しますjava.util.Date
。それはをResultSet.getDate
返すと伝えていますが、にjava.sql.Date
直接割り当てることができますjava.util.Date
。
java.sql.Date
するjava.util.Date
ときにaをa に割り当てることができるのはなぜ「伝える」のですか?あなたがしようとしている点は何ですか?
私は同じ問題を抱えていましたが、準備されたステートメントに現在の日付を挿入する最も簡単な方法はこれです:
preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));
どちらも使用しないでください。
java.time.Instant
代わる java.util.Date
java.time.LocalDate
代わる java.sql.Date
java.util.Dateとjava.sql.Date:いつ、どちらを使用するのか?
これらのクラスはどちらもひどいものであり、設計と実装に欠陥があります。ペスト コロナウイルスのように避けてください。
代わりに、JSR 310で定義されているjava.timeクラスを使用してください。これらのクラスは、日時処理を処理するための業界をリードするフレームワークです。これら取って代わるには、完全に流血ひどいレガシーのようなクラスDate
、Calendar
、SimpleDateFormat
、など。
java.util.Date
1つ目java.util.Date
は、UTCでの瞬間を表すことを意味します。つまり、UTCからのオフセットが0時間分秒です。
java.time.Instant
に置き換えられましたjava.time.Instant
。
Instant instant = Instant.now() ; // Capture the current moment as seen in UTC.
java.time.OffsetDateTime
Instant
java.timeの基本的なビルディングブロッククラスです。より柔軟性を高めるOffsetDateTime
にZoneOffset.UTC
は、同じ目的でset to を使用します:UTCで瞬間を表します。
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
JDBC 4.2以降を使用PreparedStatement::setObject
して、このオブジェクトをデータベースに送信できます。
myPreparedStatement.setObject( … , odt ) ;
取得します。
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
java.sql.Date
java.sql.Date
クラスもひどいと廃止されました。
このクラスは、日付と時間帯なしで日付のみを表すことを目的としています。残念ながら、デザインのひどいハックでは、このクラスは、(これjava.util.Date
はUTCでの時刻を持つ日付)を表すから継承されます。したがって、このクラスは単に日付のみのふりをしているだけで、実際には時刻とUTCの暗黙のオフセットを持っています。これは非常に混乱を引き起こします。このクラスを使用しないでください。
java.time.LocalDate
代わりに、java.time.LocalDate
時刻やタイムゾーン、オフセットを使用せずに、日付(年、月、日)だけを追跡するために使用します。
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate ld = LocalDate.now( z ) ; // Capture the current date as seen in the wall-clock time used by the people of a particular region (a time zone).
データベースに送信します。
myPreparedStatement.setObject( … , ld ) ;
取得します。
LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
java.timeのフレームワークは、Java 8に組み込まれており、後にされています。これらのクラスは面倒古い取って代わるレガシーのような日付時刻クラスをjava.util.Date
、Calendar
、& SimpleDateFormat
。
詳細については、Oracleチュートリアルを参照してください。スタックオーバーフローで多くの例と説明を検索してください。仕様はJSR 310です。
ジョダタイムプロジェクトは、今でメンテナンスモードへの移行をアドバイスjava.timeのクラス。
java.timeオブジェクトをデータベースと直接交換することができます。JDBC 4.2以降に準拠したJDBCドライバーを使用します。文字列もクラスも必要ありません。java.sql.*
java.timeクラスはどこで入手できますか?
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());
}
java.util.Date
ミリ秒の精度で特定の瞬間を表します。タイムゾーンなしで日付と時刻の両方の情報を表します。java.util.Dateクラスは、Serializable、Cloneable、Comparableインターフェースを実装します。それによって継承されjava.sql.Date
、java.sql.Time
そしてjava.sql.Timestamp
インターフェース。
java.sql.Date
時間情報なしで日付を表すjava.util.Dateクラスを拡張し、データベースを処理する場合にのみ使用する必要があります。SQL DATEの定義に準拠するにはjava.sql.Date
、インスタンスに関連付けられている特定のタイムゾーンで時間、分、秒、ミリ秒をゼロに設定することにより、インスタンスでラップされたミリ秒の値を「正規化」する必要があります。
それは、すべてのパブリックメソッド継承java.util.Date
などをgetHours()
、getMinutes()
、getSeconds()
、setHours()
、setMinutes()
、setSeconds()
。java.sql.Date
それから、すべての時間操作を上書き、時間情報が格納されていないjava.util.Date
と、これらの方法の全ては投げるjava.lang.IllegalArgumentException
彼らの実装の詳細から明らかなよう呼び出された場合。