為什麼阿里Java開發手冊不推薦使用Timestamp

開發手冊

不推薦用java.sql.Datejava.sql.Time網上說的文章有很多。

參考文章:一文告訴你Java日期時間API到底有多爛

但為什麼不推薦使用java.sql.Timestamp文章比較少。

原因

Oracle官網文檔中這麼寫:

可以看到,根源是因為java.sql.Timestamp父類java.sql.DatefastTime屬性存儲秒,而java.sql.Timestampnanos存儲秒以外的毫秒。所以秒和毫秒是分別存儲的,從Timestamp的構造方法也可以看出來:

public Timestamp(long time) {
	// 設置java.sql.Date的fastTime
	super((time/1000)*1000);
	// 設置java.sql.Timestamp的nanos
	
	if (nanos < 0) {
		nanos = 1000000000 + nanos;
		super.setTime(((time/1000)-1)*1000);
	}
}

所以會有什麼問題呢?

  1. equals的問題

The Timestamp.equals(Object) method never returns true when passed an object that isn’t an instance of java.sql.Timestamp, because the nanos component of a date is unknown.

可能程式設計師會想,我兩個時間都是從一個millis中創建的,那時間應該是一樣的。但是因為Timestamp的設計,它們的值不相等。

  1. after的問題

期待的答案應該是false
原因是:

    public boolean after(Date when) {
        return getMillisOf(this) > getMillisOf(when);
    }

    static final long getMillisOf(Date date) {
        if (date.cdate == null || date.cdate.isNormalized()) {
            return date.fastTime;
        }
        BaseCalendar.Date d = (BaseCalendar.Date) date.cdate.clone();
        return gcal.getTime(d);
    }
date對象的fastTime值為:     1664429777371
timestamp對象的fastTime值為:1664429777000

看一下Timestamp的構造方法:

public Timestamp(long time) {
	// 設置java.sql.Date的fastTime
	super((time/1000)*1000);
	// 設置java.sql.Timestamp的nanos
	
	if (nanos < 0) {
		nanos = 1000000000 + nanos;
		super.setTime(((time/1000)-1)*1000);
	}
}

可以知道timestamp對象的fastTime的後三位為0。

而看Date的構造方法:

    public Date(long date) {
        fastTime = date;
    }

它是直接把傳入的值賦值給fastTime。

總結

不要將java.sql.Timestamp和其它java.util.Date的對象比較。

Tags: