您好,登錄后才能下訂單哦!
提起java里面的時間戳,相信很多人都用過。
不就是java.sql.Timestamp類,兩個構造器,13個方法,這也許屬于java中最簡單的基礎類了。
俗話說淹死的都是會游泳的,同樣在開發中讓我們栽跟頭的往往都是耳熟能詳的一些類庫。
首先讓我們看看以下幾行代碼的輸出結果吧
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)); |
如果你能很明確的說出每一個輸出結果是什么以及為什么,那么你已經不需要繼續往下看了。
如果你對一個或者更多的結果感到迷茫,就讓我們來一起踩踩坑吧。
要搞清楚Timestamp類的范圍方法有很多,可以看文檔、看源代碼,寫個代碼測試一下或者搜索引擎看看別人怎么說。
當我們實踐了上面的一種或者多種方法后我們再回過頭來看看我們引子里的第一段和第二段代碼的輸出結果。
Timestamp t1 = new Timestamp(0); System.out.println(t1);//1970-01-01 08:00:00.0 |
有沒有看著很熟悉?跟格林尼治標準時(計算機用的比較多的說法是UTC)就差8個小時,那也很好理解我們是東八區嘛。
換句話說Timestamp類的開始時間可以認為是格林尼治標準時,在不同時區使用會加上時區的偏移量。
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 |
上面幾段代碼其實都是根據網上關于Timestamp的最大值做出的驗證
可以發現獲取出來的毫秒數和Integer.MAX_VALUE差不多就是1000倍的差距,
那不妨推斷一下這種說法的依據是在32位系統中存儲毫秒數,無溢出情況下的最大月末或者年末。
接下來通過Integer.MAX_VALUE構造出來的時間(t3)是2038-01-19 11:14:07.0 也驗證了我們的推斷。
這個時間是我們在目前時間格式下的最大時間了,通過t21,t22的驗證發現通過,Timestamp類是可以存儲這種時間的。
再回過頭去看源代碼,發現用于存儲毫秒數的是Long而不是Integer,64位的Long完全可以到9999年嘛。
通過上面的驗證我們可以確認Timestamp類的最大時間可以是9999-12-31 23:59:59
Tips:
實際使用的時候我們的數據需要存儲到數據庫。
以mysql為例,如果你想當然的將java的Timestamp直接就對應到數據庫的Timestamp,你會發現兩個數據類型范圍并不一樣。
摘抄一段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.
在真實使用的時候將業務,java類庫,數據庫數據類型進行對照,盡可能的找出符合要求的組合。
用到了時間,當然不能不比較了,看看下面這段代碼的輸出吧
Date d1 = new Date(0); System.out.println(d1.equals(t1));//true System.out.println(t1.equals(d1));//false |
很有意思的結果,我們先來看看他是怎么做到的吧,看源碼>>
Date.equals:
public boolean equals(Object obj) { return obj instanceof Date && getTime() == ((Date) obj).getTime();} |
由于Timestamp是繼承自Date,并且在強轉后高精度部分丟失導致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;
代碼沒毛病,可是回到現實世界不就是說a = b 而b != a嗎,作為一個嚴謹的程序員是不是總感覺哪里不舒服呢?
相信作者也是這樣,先是在類上出現了這段說明
The inheritance relationship between
Timestamp
andjava.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.
大意就是:我寫這個繼承關系只是實現繼承并不是類型繼承(為了少寫點代碼,其實沒毛關系),equals方法和父類的equals方法不對等(你們用錯了我不負責啊)
最后總結以下幾點
1, java.sql.Timestamp可以接受的時間范圍是1970-01-01 00:00:00 - 9999-12-31 23:59:59,具體使用的時候需要考慮時區帶來的偏移量
2, 和數據庫結合使用需要結合實際需求、數據庫數據類型的具體范圍選擇合適的范圍,不能僅僅通過名字來選擇數據類型
3, Timestamp類的equals方法和父類的equals方法并不是對等的,只有兩個比較的對象都是Timestamp的時候才能返回一致的結果
4, 我們在實際設計開發的時候盡量避免這種不舒服的設計,結合繼承,封裝,多態等多種手段確保我們設計的魯棒。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。