溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

你可能不會注意的Timestamp

發(fā)布時間:2020-07-04 06:52:26 來源:網(wǎng)絡(luò) 閱讀:5178 作者:chellman 欄目:軟件技術(shù)

提起java里面的時間戳,相信很多人都用過。
不就是java.sql.Timestamp類,兩個構(gòu)造器,13個方法,這也許屬于java中最簡單的基礎(chǔ)類了。

俗話說淹死的都是會游泳的,同樣在開發(fā)中讓我們栽跟頭的往往都是耳熟能詳?shù)囊恍╊悗臁?/span>

引子

首先讓我們看看以下幾行代碼的輸出結(jié)果吧


Timestamp t1 = new Timestamp(0);
System.out.println(t1);
Timestamp t2 = Timestamp.valueOf("2037-12-31 23:59:59");
System.out.println(t2.getTime());
System.out.println(t2.getTime() == new Long(Integer.MAX_VALUE) * 1000);
Timestamp t3 = new Timestamp(new Long(Integer.MAX_VALUE) * 1000);
System.out.println(t3);Timestamp t21 = Timestamp.valueOf("9999-12-31 23:59:59");
System.out.println(t21.getTime());
Timestamp t22 = new Timestamp(t21.getTime());
System.out.println(t22);Date d1 = new Date(0);
System.out.println(d1.equals(t1));
System.out.println(t1.equals(d1));

如果你能很明確的說出每一個輸出結(jié)果是什么以及為什么,那么你已經(jīng)不需要繼續(xù)往下看了。
如果你對一個或者更多的結(jié)果感到迷茫,就讓我們來一起踩踩坑吧。

時間范圍

要搞清楚Timestamp類的范圍方法有很多,可以看文檔、看源代碼,寫個代碼測試一下或者搜索引擎看看別人怎么說。
當我們實踐了上面的一種或者多種方法后我們再回過頭來看看我們引子里的第一段和第二段代碼的輸出結(jié)果。


Timestamp t1 = new Timestamp(0);
System.out.println(t1);//1970-01-01 08:00:00.0

有沒有看著很熟悉?跟格林尼治標準時(計算機用的比較多的說法是UTC)就差8個小時,那也很好理解我們是東八區(qū)嘛。
換句話說Timestamp類的開始時間可以認為是格林尼治標準時,在不同時區(qū)使用會加上時區(qū)的偏移量。


Timestamp t2 = Timestamp.valueOf("2037-12-31 23:59:59");
System.out.println(t2.getTime());//2145887999000
System.out.println(t2.getTime() == new Long(Integer.MAX_VALUE) * 1000);//false
Timestamp t3 = new Timestamp(new Long(Integer.MAX_VALUE) * 1000);
System.out.println(t3);//2038-01-19 11:14:07.0
Timestamp t21 = Timestamp.valueOf("9999-12-31 23:59:59");
System.out.println(t21.getTime());//253402271999000
Timestamp t22 = new Timestamp(t21.getTime());
System.out.println(t22);//9999-12-31 23:59:59.0

上面幾段代碼其實都是根據(jù)網(wǎng)上關(guān)于Timestamp的最大值做出的驗證

第一種 2037-12-31 23:59:59(t2)

可以發(fā)現(xiàn)獲取出來的毫秒數(shù)和Integer.MAX_VALUE差不多就是1000倍的差距,
那不妨推斷一下這種說法的依據(jù)是在32位系統(tǒng)中存儲毫秒數(shù),無溢出情況下的最大月末或者年末。
接下來通過Integer.MAX_VALUE構(gòu)造出來的時間(t3)是2038-01-19 11:14:07.0 也驗證了我們的推斷。

第二種 9999-12-31 23:59:59

這個時間是我們在目前時間格式下的最大時間了,通過t21,t22的驗證發(fā)現(xiàn)通過,Timestamp類是可以存儲這種時間的。
再回過頭去看源代碼,發(fā)現(xiàn)用于存儲毫秒數(shù)的是Long而不是Integer,64位的Long完全可以到9999年嘛。

通過上面的驗證我們可以確認Timestamp類的最大時間可以是9999-12-31 23:59:59

Tips:
實際使用的時候我們的數(shù)據(jù)需要存儲到數(shù)據(jù)庫。
mysql為例,如果你想當然的將java的Timestamp直接就對應(yīng)到數(shù)據(jù)庫的Timestamp,你會發(fā)現(xiàn)兩個數(shù)據(jù)類型范圍并不一樣。
摘抄一段mysql官方文檔的說明:

The DATE type is used for values with a date part but no time part. MySQL retrieves and displays DATE values in ‘YYYY-MM-DD’ format. The supported range is ‘1000-01-01’ to ‘9999-12-31’. The DATE type is used for values with a date part but no time part. MySQL retrieves and displays DATE values in ‘YYYY-MM-DD’ format. The supported range is ‘1000-01-01’ to ‘9999-12-31’.
The DATETIME type is used for values that contain both date and time parts. MySQL retrieves and displays DATETIME values in ‘YYYY-MM-DD HH:MM:SS’ format. The supported range is ‘1000-01-01 00:00:00’ to ‘9999-12-31 23:59:59’.
The TIMESTAMP data type is used for values that contain both date and time parts. TIMESTAMP has a range of ‘1970-01-01 00:00:01’ UTC to ‘2038-01-19 03:14:07’ UTC.


在真實使用的時候?qū)I(yè)務(wù),java類庫,數(shù)據(jù)庫數(shù)據(jù)類型進行對照,盡可能的找出符合要求的組合。

Equals并不相等

用到了時間,當然不能不比較了,看看下面這段代碼的輸出吧


Date d1 = new Date(0);
System.out.println(d1.equals(t1));//true
System.out.println(t1.equals(d1));//false

很有意思的結(jié)果,我們先來看看他是怎么做到的吧,看源碼>>
Date.equals:


public boolean equals(Object obj) {	return obj instanceof Date && getTime() == ((Date) obj).getTime();}

由于Timestamp是繼承自Date,并且在強轉(zhuǎn)后高精度部分丟失導(dǎo)致getTime完全一致,所以第一個比較返回了true

Timestamp.equals:


public boolean equals(java.lang.Object ts) {
	if (ts instanceof Timestamp) {
		return this.equals((Timestamp)ts);	
		} else {
			return false;	}
			}

判斷Date并不是Timestamp類型,直接返回false;

代碼沒毛病,可是回到現(xiàn)實世界不就是說a = b 而b != a嗎,作為一個嚴謹?shù)某绦騿T是不是總感覺哪里不舒服呢?

相信作者也是這樣,先是在類上出現(xiàn)了這段說明

The inheritance relationship between Timestamp and java.util.Date really denotes implementation inheritance, and not type inheritance.

然后方法上還要補上

Note: This method is not symmetric with respect to the equals(Object) method in the base class.

大意就是:我寫這個繼承關(guān)系只是實現(xiàn)繼承并不是類型繼承(為了少寫點代碼,其實沒毛關(guān)系),equals方法和父類的equals方法不對等(你們用錯了我不負責?。?/span>

總結(jié)

最后總結(jié)以下幾點
1, java.sql.Timestamp可以接受的時間范圍是1970-01-01 00:00:00 - 9999-12-31 23:59:59,具體使用的時候需要考慮時區(qū)帶來的偏移量
2, 和數(shù)據(jù)庫結(jié)合使用需要結(jié)合實際需求、數(shù)據(jù)庫數(shù)據(jù)類型的具體范圍選擇合適的范圍,不能僅僅通過名字來選擇數(shù)據(jù)類型
3, Timestamp類的equals方法和父類的equals方法并不是對等的,只有兩個比較的對象都是Timestamp的時候才能返回一致的結(jié)果
4, 我們在實際設(shè)計開發(fā)的時候盡量避免這種不舒服的設(shè)計,結(jié)合繼承,封裝,多態(tài)等多種手段確保我們設(shè)計的魯棒。


向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI