java.util.Date.compareTo(java.sql.Timestamp time)は危ない。

System.out.println(new java.util.Date(10000).before(new java.sql.Timestamp(20000)));
System.out.println(new java.util.Date(10000).before(new java.sql.Timestamp(10999)));

上記1行目では"true"を返す。基準時から10000ミリ秒経過後の時間は基準時から20000ミリ秒経過後の時間よりも前なので、この挙動は正しい。
でも、2行目では"false"を返す、微妙な挙動がある。ってかバグだわ、こりゃ。そういうのを含めて、仕様だそうです。

なんで?

java.util.Date(long time)では、timeをミリ秒単位として解釈し、その全ての値をthis.fastTime に格納する。一方でjava.sql.Timestamp(long time)では、秒単位以上の値をsuper.fastTimeに格納し、秒の小数点以下の値をthis.nanosに格納する。このとき、Date.compareTo(Date ahotherDate)を使って比較すると、Dateオブジェクトの内部ではTimestamp.nanosを無視され、Date.fastTimeのみを比較するのでTimestampクラスの秒の小数点以下の値は無視されてしまう。

    public Date(long date) {
        fastTime = date;
    }
    //中略
    public int compareTo(Date anotherDate) {
	long thisTime = getMillisOf(this);
	long anotherTime = getMillisOf(anotherDate);
	return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1));
    }
    public Timestamp(long time) {
	super((time/1000)*1000);
	nanos = (int)((time%1000) * 1000000);
	if (nanos < 0) {
	    nanos = 1000000000 + nanos;	    
	    super.setTime(((time/1000)-1)*1000);
	}
    }

どうしても比較する場合は、

java.sql.Timestamp側から比較するしかない。

System.out.println(new java.sql.Timestamp(10000).before(new java.util.Date(20000)));
System.out.println(new java.sql.Timestamp(10000).before(new java.util.Date(10999)));

nanosにはミリ秒未満を格納させればよかったのに、ね。

バグじゃない、仕様だってさ。

上記のような Timestamp クラスと java.util.Date クラスの違いのため、Timestamp 値は java.util.Date のインスタンスとして考えないでください。Timestamp と java.util.Date の継承関係は、型の継承ではなく、実装の継承を示します。
Oracle Technology Network for Java Developers | Oracle Technology Network | Oracle

まさか、この定型文の出番だとは思わなかったwww
こういうのが駄目な継承って言われるんだろうなぁ。