java.util.Dateとjava.sql.Date


回答:


585

おめでとうございます。JDBC:日付クラスの処理で私のお気に入りのペットピートをヒットしました。

基本的に、データベースは通常、日付、時刻、タイムスタンプの少なくとも3つの形式の日時フィールドをサポートしています。これらのそれぞれに対応するJDBCのクラスがあり、それぞれが拡張されjava.util.Dateます。これら3つそれぞれのクイックセマンティクスは次のとおりです。

  • java.sql.DateSQL DATEに対応します。これは、年、月、日を格納し時、分、秒、ミリ秒は無視されることを意味します。さらにsql.Date、タイムゾーンに関連付けられていません。
  • java.sql.TimeSQL 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のこの部分を完全に回避できます。


17
いい答えだ。しかし、DBAにとって少し不親切な日付を格納するのではないでしょうか。
cherouvim 2010

26
おそらく、しかし、DBA:は一般的にRDBMSを選択し、そのRDBMSに関係のないすべてのものを直接拒否する傾向があります(私はOracleファンです)。Javaアプリケーションはそれらすべてで動作することが期待されています。個人的には自分のロジックをDBに入れたくありません。
Esko

2
私のmysql列は日時ですが、ps.setDate(new java.sql.Date(myObject.getCreatedDate()。getTime()));を実行しています。ミリ秒の部分を失っています。これを修正するにはどうすればよいですか?
ブランクマン2012

2
ミリ秒を失わないために:新しいjava.sql.Timestamp(utilDate.getTime())
Kieveli

3
これはTZ固有であることが一般的なバグであることを述べましたが、仕様ではそうすべきではありません。
Esko

60

後期編集: Java 8 以降では、回避することも回避することjava.util.Datejava.sql.Dateできず 、代わりにjava.time(Jodaに基づく)パッケージを使用することをお勧めします。Java 8を使用していない場合、元の応答は次のとおりです。


java.sql.Date-(JDBCのような)それを使用するライブラリのメソッド/コンストラクタを呼び出すとき。そうでなければ。JDBCを明示的に処理しないアプリケーション/モジュールのデータベースライブラリに依存関係を導入したくない場合。

java.util.Date-それを使用するライブラリを使用する場合。それ以外の場合は、いくつかの理由により、可能な限り少なくします。

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

  • それは日付をあまりうまく処理しません。あなたのような人々を本当に後退させます。

  • 今、juDはうまく機能しないため、恐ろしいCalendarクラスが導入されました。また、それらは変更可能であり、操作がひどいため、選択の余地がない場合は回避する必要があります。

  • Joda Time APIJava 7になり、新しい公式の日付処理APIになる可能性もあります - クイック検索ではそうはなりません)など、より優れた代替手段があります。

longJodaのような新しい依存関係を導入するのはやり過ぎだと感じる場合は、オブジェクトのタイムスタンプフィールドにsを使用するのはそれほど悪いことではありませんが、私自身は通常、タイプセーフとドキュメント化のために、それらを渡すときにjuDでラップします。


5
データベースに格納するとき、なぜjava.sqlよりもjava.timeを優先する必要があるのですか 私は声明の中で、本当に面白いんだけど、私は、なぜ:)理解したい
ジャン=フランソワ・Savard

ジャンFrançoisSavard@私はあなたがそのコメントを掲載するので、あなたの質問に対する答えを見つけた願っています-しかし、ここでは単に酒完全を期すため、答えだ:それはまだ完全にOKだjava.sql.DatePreparedStatementなど!あなたはしているが、それを周りに渡す場合でも、使用LocalDate、使用して変換しているjava.sql.Date.valueOfjava.sql.Date.valueOf、それを設定するとき、および使用可能な限り早期に戻ってそれを変換するjava.sql.Date.toLocalDate あなたはできるだけのjava.sqlが関与したいので、それが可変なので、再び- 。
gustafc

19

使用するのjava.sql.DatePreparedStatement.setDate。それ以外の場合は、を使用しますjava.util.Date。それはをResultSet.getDate返すと伝えていますが、にjava.sql.Date直接割り当てることができますjava.util.Date


3
Ehm、ResultSet#getDate()はsql.Date(util.Dateを拡張)を返します。
Esko、2010

3
@Esko-「Ehm」、コメント(および反対票)する前に修正しました。
ポールトンブリン

1
java.sql.Dateをjava.util.Dateに割り当てることができる理由は、最初のものが2番目のサブクラスであるためであることに注意することが重要です。
dj18

2
前者が後者を拡張java.sql.Dateするjava.util.Dateときにaをa に割り当てることができるのはなぜ「伝える」のですか?あなたがしようとしている点は何ですか?
ローンの侯爵2013

11

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

preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));

2
これでタイムゾーンを取得できません。
erhanasikoglu 2015年

4

tl; dr

どちらも使用しないでください。

どちらでもない

java.util.Dateとjava.sql.Date:いつ、どちらを使用するのか?

これらのクラスはどちらもひどいものであり、設計と実装に欠陥があります。ペスト コロナウイルスのように避けてください。

代わりに、JSR 310で定義されているjava.timeクラスを使用してください。これらのクラスは、日時処理を処理するための業界をリードするフレームワークです。これら取って代わるには、完全に流血ひどいレガシーのようなクラスDateCalendarSimpleDateFormat、など。

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

Instantjava.timeの基本的なビルディングブロッククラスです。より柔軟性を高めるOffsetDateTimeZoneOffset.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(レガシーとモダンの両方)および標準SQLの日時タイプの表


java.timeについて

java.timeのフレームワークは、Java 8に組み込まれており、後にされています。これらのクラスは面倒古い取って代わるレガシーのような日付時刻クラスをjava.util.DateCalendar、& SimpleDateFormat

詳細については、Oracleチュートリアルを参照してください。スタックオーバーフローで多くの例と説明を検索してください。仕様はJSR 310です。

ジョダタイムプロジェクトは、今でメンテナンスモードへの移行をアドバイスjava.timeのクラス。

java.timeオブジェクトをデータベースと直接交換することができます。JDBC 4.2以降に準拠したJDBCドライバーを使用します。文字列もクラスも必要ありません。java.sql.*

java.timeクラスはどこで入手できますか?

JavaまたはAndroidのどのバージョンで使用するjava.timeライブラリの表


1
伝染病の参照をコロナウイルスで置き換えることへの賛成票。もっと共感できるようになりました。
ankuranurag2

2

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

0

java.util.Dateミリ秒の精度で特定の瞬間を表します。タイムゾーンなしで日付と時刻の両方の情報を表します。java.util.Dateクラスは、Serializable、Cloneable、Comparableインターフェースを実装します。それによって継承されjava.sql.Datejava.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彼らの実装の詳細から明らかなよう呼び出された場合。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.