Hatena::ブログ(Diary)

yvsu pron. yas このページをアンテナに追加 RSSフィード

2009-02-19

java.util.Dateをjava.sql.Dateにきちんと変換する方法

多くの人はこうやればいいと思っているかもしれません。

java.util.Date d = new java.util.Date();
java.sql.Date d2 = new java.sql.Date(d.getTime());

確かにこれでも一応変換はできますが、きちんと変換してはいません。java.sql.DateのJavadocを見るとこう書いてあります。


SQL DATE の定義に対応させるために、java.sql.Date のインスタンスでラップされたミリ秒の値は、インスタンスが関連した特定のタイムゾーン時間、分、秒、ミリ秒をゼロに設定することで、「標準化」する必要があります。


つまり、java.util.Date#getTime()をjava.sql.Dateにただ渡すだけでは不十分で、「特定のタイムゾーン時間、分、秒、ミリ秒をゼロに設定しなければいけない」のです。それも、開発者が。

では、きちんと変換するコードを見てみましょう。

java.util.Date d = new java.util.Date();
Calendar cal = Calendar.getInstance();
cal.setTime(d);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
java.sql.Date d2 = new java.sql.Date(cal.getTimeInMillis());

ちなみに、java.util.Dateをjava.sql.Timeに変換するには次のようにします。

java.util.Date d = new java.util.Date();
Calendar cal = Calendar.getInstance();
cal.setTime(d);
cal.set(Calendar.YEAR, 1970);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DATE, 1);
java.sql.Time t = new java.sql.Time(cal.getTimeInMillis());

TimeにわたすUTCの値は、1970-01-01の時間にしなければいけません。

aufhebenaufheben 2009/02/19 22:44 ちなみに、java.sql.Time って精度が秒までしかないけれど、ミリ秒は保持したままでいいんでしょうかね? 素朴な疑問です。

higayasuohigayasuo 2009/02/20 10:45 Timeの精度が秒までというのは、どこかに書いてありますか。
Javadoc上は、「ゼロエポック」値を 1970 年 1 月 1 日に設定しなければならない
としか、書いてありません。

aufhebenaufheben 2009/02/21 11:59 曖昧な書き方だけれど、
http://java.sun.com/javase/ja/6/docs/ja/technotes/guides/jdbc/getstart/mapping.html#1007474
> JDBC TIME 型は、時刻、分、秒で構成される。
あと、コンストラクタ、toString、valueOf なども秒までしか対応していませんし。

higayasuohigayasuo 2009/02/22 10:30 SQL Timeが秒までなら、
cal.set(Calendar.MILLISECOND, 0);
もやるべきですね。
修正しておきます。

nakazeenakazee 2009/02/22 12:31 開発ではjava.sql.Dateは非推奨にすべきです。Driverにより仕様が違うことを理解しないプログラマが多すぎます。Dateはequalsメソッドの定義が曖昧でDTOとして使い物になりません。

koichikkoichik 2009/02/22 14:00 「SQL:1999 リレーショナル言語詳解」によると,標準 SQL における TIME 型の秒は,任意の桁数の小数部を持つことができるそうです (つまり標準 SQL では MILLISECOND は秒の一部).なので,必ずしもミリ秒を 0 にする必要があるとは限らないということになりそう.
なお,標準 SQL における TIMESTAMP の秒は,最低 6 桁の小数部を持つ必要があり,java.sql.Timestamp はそれに対応してますね.

koichikkoichik 2009/02/22 14:30 aufheben さんが書いてるリンク先を見ると,java.sql.Date については「ミリ秒フィールドにはゼロが設定される必要がある」と明確に書いてあるのに,java.sql.Time については書かれていません.

higayasuohigayasuo 2009/02/22 14:48 おっと、java.sql.Timeのjavadoc通りということですね。
修正しておきます。

薄学者薄学者 2009/04/26 00:47 こうしないとどういう問題が起きるのか教えてもらえませんか?

gaohgaoh 2009/12/07 10:57 equalsやcompareToが意図しない結果を返しちゃうんじゃないですかね。

tsuyoshitsuyoshi 2012/04/13 20:22 なんかここまでいろいろあると、DateUtilみたいなクラスでクラスメソッドで正式な変換手順を提供してほしいですね...

harukaharuka 2012/11/13 23:44 過去の文章にコメントしてしまって申し訳ないです。
現在のJava開発でまさに「java.util.Dateをjava.sql.Date」の逆変換【java.sql.Dateをjava.util.Dateに変換】を行わなければいけない状況になりました。
その場合の実装方法について教えていただけないでしょうか。

投稿したコメントは管理者が承認するまで公開されません。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証