ひがやすを blog このページをアンテナに追加 RSSフィード

Information

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通りということですね。
修正しておきます。

ゲスト