このコードをテストするとき:
Java.util.Date date = new Java.util.Date();
Java.util.Date stamp = new Java.sql.Timestamp(date.getTime());
assertTrue(date.equals(stamp));
assertTrue(date.compareTo(stamp) == 0);
assertTrue(stamp.compareTo(date) == 0);
assertTrue(stamp.equals(date));
私は真、真、真、偽を期待するでしょう。このため:
Java.sql.Timestampのjavadocでは、次のように記述されています。
注:このタイプは、Java.util.Dateと個別のナノ秒値の複合です。整数秒のみがJava.util.Dateコンポーネントに格納されます。秒の小数部-ナノ-は独立しています。 Timestamp.equals(Object)メソッドは、日付のnanosコンポーネントが不明であるため、Java.util.Date型の値が渡されたときにtrueを返すことはありません。その結果、Timestamp.equals(Object)メソッドは、Java.util.Date.equals(Object)メソッドに対して対称ではありません。また、hashcodeメソッドは基盤となるJava.util.Date実装を使用するため、計算にnanoを含めません。
上記のTimestampクラスとJava.util.Dateクラスの違いにより、コードはTimestamp値をJava.util.Dateのインスタンスとして一般的に表示しないことをお勧めします。 TimestampとJava.util.Dateの間の継承関係は、型の継承ではなく実装の継承を実際に示しています。
しかし、代わりに、true、false、true、falseを取得します。何か案は?
編集:この問題は、equalsメソッドで2つのDateをチェックしているときに表示されますが、Dateオブジェクトの1つはHibernateクラスから来ており、デバッグにはオブジェクトにTimeStampが含まれていることがわかります。したがって、equalsメソッドはfalseと評価され、次にこれを見つけました: http://mattfleming.com/node/141
しかし、コードを試してみると、異なる結果が得られます... equalsとcompareToのどちらも使用できない場合、2つの日付が同じであるかどうかを確認するために何を使用する必要がありますか?!?!
面倒なレガシー日時クラスの代わりに、最新のJava.timeクラスを使用してください。
myPreparedStatement.setObject(
… ,
Instant.now() // Capture the current moment in UTC.
)
もっと率直に言って、Java.sql.Timestamp/.Date/.Timeクラスはハックであり、悪いハックです。 Java.util.Date/.Calendarと同様に、これらは設計の選択が不十分な結果です。
Java.sqlタイプはできる限り短時間使用する必要があり、データベースのデータの送受信にのみ使用します。ビジネスロジックやその他の作業には使用しないでください。
古い日時クラスは、Java 8以降に組み込まれた Java.time フレームワークに置き換えられました。これらの新しいクラスはJSR 310によって定義され、非常に成功したJoda-Timeライブラリに触発され、ThreeTen-Extraプロジェクトによって拡張されています。
最終的に、JDBCドライバーが更新され、これらのJava.time型と直接連携するようになります。ただし、その日までは、Java.sql型との間で変換を行う必要があります。そのような変換では、古いクラスに追加された 新しいメソッドを呼び出します 。
Instant
は、UTCのタイムライン上の ナノ秒 の解像度です。
Instant instant = myJavaSqlTimestamp.toInstant();
他の方向に進むには:
Java.sql.Timestamp ts = Java.sql.Timestamp.valueOf( instant );
タイムゾーンを適用して、 実時間 を取得します。
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
Java.timeクラスには、賢明に選択されたクラス設計があります。したがって、equals
とcompareTo
を期待どおりに使用できます。 UTCからのオフセットまたはタイムゾーンを持つクラスは、isEqual
、isBefore
、およびisAfter
メソッドも提供することに注意してください。これらの方法は、タイムライン上の瞬間、それらの時系列順を考慮して比較します。 equals
およびcompareTo
メソッドは、オフセットまたはタイムゾーンも考慮します。
Java.sqlの使用を最小限に抑えながら、Java.timeの使用を最大限にすると、質問の問題が浮き彫りになります。
Hibernateでは、Java.timeのコンバーターを使用します。
JDBC 4.2以降では、レガシークラスをまったく使用する必要はありません。 getObject
およびsetObject
メソッドを介して、データベースとJava.timeオブジェクトを直接交換できます。
myPreparedStatement.setObject( … , instant ) ;
そして検索。
Instant instant = myResultSet.getObject( … , Instant.class ) ;
多くのデータベースは、Java.timeで使用されているナノ秒ほどの解像度で瞬間を保存できないことに注意してください。 JDBCドライバー を暗黙的にそうするのではなく、明示的に切り捨てることができます。
Instant instant = Instant.now().truncatedTo( ChronoUnit.MILLIS ) ; // Lop off any nanoseconds & microseconds, keeping only the milliseconds, to match limitations of database.
Java.time フレームワークは、Java 8以降に組み込まれています。これらのクラスは、 Java.util.Date
、 Calendar
、& SimpleDateFormat
などの厄介な古い レガシー 日時クラスに取って代わります。
Joda-Time プロジェクトは、現在 メンテナンスモード であり、 Java.time クラスへの移行を推奨しています。
詳細については、 Oracleチュートリアル を参照してください。また、Stack Overflowで多くの例と説明を検索してください。仕様は JSR 31 です。
Java.timeオブジェクトをデータベースと直接交換できます。 JDBC 4.2 以降に準拠する JDBCドライバー を使用します。文字列も、Java.sql.*
クラスも必要ありません。
Java.timeクラスはどこで入手できますか?
ThreeTen-Extra プロジェクトは、追加のクラスでJava.timeを拡張します。このプロジェクトは、Java.timeに将来追加される可能性のある証明の場です。 Interval
、 YearWeek
、 YearQuarter
、 more などの便利なクラスがあります。
ニカンはequals
部分について、compareTo
について説明しました:
Timestamp
には、内部的にTimestamp
に変換するcompareTo(Date)
メソッドがありますDate
はダウンキャストによって比較を行います(Timestamp
はそのサブクラスであるため);ただし、javadocの状態:「TimestampとJava.util.Dateの間の継承関係は、型の継承ではなく実装の継承を実際に示します」私の意見では、これはもちろん恐ろしいアイデアです。
比較したいテストでも同じ問題が発生しましたJava.util.Date
およびJava.sql.Timestamp
オブジェクト。
私はそれらをLocalDate
に変換しましたが、うまくいきました:
import org.Apache.commons.lang.ObjectUtils;
// date1 and date2 can be Java.util.Date or Java.sql.Timestamp
boolean datesAreEqual = ObjectUtils.equals(toLocalDate(date1), toLocalDate(date2));
ここで、toLocalDate
は次のとおりです。
import org.joda.time.LocalDate;
import Java.util.Date;
public static void LocalDate toLocalDate(Date date)
{
return date != null ? LocalDate.fromDateFields(date) : null;
}
date.equals(stamp)はtrueを返し、スタンプequals(date)はfalseを返します。 [〜#〜] reason [〜#〜]:日付はタイムスタンプのナノ秒部分を無視し、他の部分は偶然等しいため、結果は等しい。秒の小数部-nanos-は分離されています。日付のnanosコンポーネントが不明なため、Timestamp.equals(Object)メソッドは、Java.util.Date型の値を渡されたときにtrueを返しません。詳細については here を参照してください
Timestamp
のnanos値はナノ秒数ではありません-ナノ秒分解能のミリ秒(つまり、秒の小数部)です。そのため、Timestamp
コンストラクターでは、スーパーの時間をミリ秒なしに設定しています。したがって、Timestamp
は、対応するfastTime
(もちろん、秒の小数部がない場合)よりも、メンバーDate
(DateのcompareTo()
で使用)の値が常に低くなります。
タイムスタンプのソース 110行目を確認します。
このような「文字列」を使用してオブジェクトの日付を再作成してください
Date date = new Date();
Date stamp = Timestamp(date.getTime());
SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String date1String = ft.format(date);
String date2String = ft.format(stamp);
Date date1 = ft.parse(date1String);
Date date2 = ft.parse(date2String);
assertTrue(date1.equals(date2)); // true
assertTrue(date1.compareTo(date2) == 0); //true
assertTrue(date2.compareTo(date1) == 0); //true
assertTrue(date2.equals(date1)); // true
DateとTimeStampの両方をCalendarオブジェクトに変換することを解決し、単一のCalendarのプロパティを比較しました。
Calendar date = Calendar.getInstance();
date.setTimeInMillis(dateObject.getTime());
Calendar timestamp = Calendar.getInstance();
timestamp.setTimeInMillis(timestampObject.getTime());
if (effettoAppendice.get(Calendar.DAY_OF_MONTH) == timestamp.get(Calendar.DAY_OF_MONTH) &&
effettoAppendice.get(Calendar.MONTH) == timestamp.get(Calendar.MONTH) &&
effettoAppendice.get(Calendar.YEAR) == timestamp.get(Calendar.YEAR)) {
System.out.println("Date and Timestamp are the same");
} else {
System.out.println("Date and Timestamp are NOT the same");
}
お役に立てれば。
悲しいことに、Timestamp
クラスはequals(Object)
メソッドをequals(Timestamp)
でオーバーロードするため、タイムスタンプでの比較は困難です。
equals(Object)
では、javadocsは次のように述べています。
このTimestampオブジェクトが指定されたオブジェクトと等しいかどうかをテストします。メソッドequalsのこのバージョンは、Timestamp.equals(Timestamp)の不正な署名を修正し、既存のクラスファイルとの下位互換性を維持するために追加されました。注:このメソッドは、基本クラスのequals(Object)メソッドに関して対称ではありません。
私の経験則では、タイムスタンプの等価性を比較することはありません(とにかくほとんど役に立たない)が、等価性をチェックする必要がある場合は、getTime()
(1月からのミリ秒数1970年1月、00:00)。
実装の継承と型の継承に関する小さなメモ。
「オブジェクトのクラスは、オブジェクトの実装方法を定義します。対照的に、オブジェクトの型は、そのインターフェースのみを参照します。クラス継承別の場所で使用できます。 "
JAVADOCが述べたように、タイムスタンプと日付クラスには実装の継承があります。
タイムスタンプのソースコード比較方法をご覧ください。
public boolean equals(Java.lang.Object ts) {
if (ts instanceof Timestamp) {
return this.equals((Timestamp)ts);
} else {
return false;
}
}
http://www.docjar.com/html/api/Java/sql/Timestamp.Java.html
比較オブジェクトがタイムスタンプの場合にのみtrueを返します。また、ここに日付のソースコードがあります: http://www.docjar.com/html/api/Java/util/Date.Java.html 、およびTimestampはDateを継承するため、比較できます。