深入了解Java.Util.Date詳情
前言:
很少有類能像java.util.Date那樣在堆棧溢出方面引起如此多的類似問題,有四個原因:
- 日期和時間工作基本上相當復雜,而且充滿了拐彎抹角的情況。這是可以管理的,但你確實需要花一些時間來理解它。
java.util.Date類在很多方面都很糟糕(詳情如下)。- 一般來說,開發(fā)人員對它的理解很差。
- 它被庫作者嚴重濫用,進一步加劇了混亂。
了解java.util.Date最重要的事情為:
- 如果可能的話,你應該避免。使用
java.time.*如果可能的話,也可以使用ThreeTen Backport(基本上是舊版本的java.time)或Joda time(如果您還沒有使用java 8)。 - 如果您被迫使用它,請避免使用不推薦使用的成員。近20年來,它們中的大多數(shù)都被棄用了,這是有充分理由的。
- 如果您真的覺得必須使用不推薦的成員,請確保您真正理解他們。
- Date實例表示時間上的一個瞬間,而不是日期。重要的是,這意味著:
- 它沒有時區(qū)。
- 它沒有格式。
- 它沒有日歷系統(tǒng)。
現(xiàn)在,關于細節(jié)…
Java.Util.Date有什么問題?
java.util.Date(從現(xiàn)在開始就是Date)是一種糟糕的類型,這解釋了為什么Java 1.1中有這么多的Date被棄用(但不幸的是,它仍然在使用)。
設計缺陷包括:
- 它的名字令人誤解:它不代表日期,它代表的是時間上的一個瞬間。因此,它應該被稱為Instant,就像它的
java.time一樣等效。 - 這是非最終結(jié)果:這鼓勵了java等繼承的不當使用。
java.sql.Date(表示日期,由于具有相同的短名稱,因此也容易混淆) - 它是可變的:日期/時間類型是由不可變類型有效建模的自然值。日期是可變的(例如通過
setTime方法),這意味著勤奮的開發(fā)人員最終會在各地創(chuàng)建防御副本。 - 它在許多地方隱式使用系統(tǒng)本地時區(qū),包括
toString(),這讓許多開發(fā)人員感到困惑。 - 它的月份編號是以0為基礎的,是從C復制的。這導致了很多很多錯誤。
- 它的年份編號是基于1900年的,也是從C中復制的。當然,當Java問世時,我們已經(jīng)有了這樣一個想法,即這對可讀性不利?
- 其方法的名稱不明確:
getDate()返回月份的第幾天,getDay()返回星期幾。給這些更具描述性的名字有多難? - 它是否支持閏秒是不明確的:“一秒由0到61之間的整數(shù)表示;值60和61只在閏秒中出現(xiàn),甚至僅在實際正確跟蹤閏秒的Java實現(xiàn)中出現(xiàn)。”我強烈懷疑大多數(shù)開發(fā)人員(包括我自己)都做了大量假設,認為
getSeconds()的范圍實際上在0-59(包括0-59)之間。 - 沒有明顯的理由,它是寬大的:“在所有情況下,為這些目的而給出的方法的參數(shù)都不需要在指定的范圍內(nèi);例如,日期可以指定為1月32日,也可以解釋為2月1日。”這是否有用?
我可以發(fā)現(xiàn)更多的問題,但他們會越來越挑剔。這是一個非常豐富的列表。好的一面是:
- 它明確地表示一個值:時間上的一個瞬間,沒有相關的日歷系統(tǒng)、時區(qū)或文本格式,精確到毫秒。
不幸的是,開發(fā)人員對這一“好方面”的理解也很差。讓我們把它打開…
什么是“瞬間”
注意:在這篇文章的其余部分,我忽略了相對論和閏秒。它們對一些人來說非常重要,但對大多數(shù)讀者來說,它們只會帶來更多的困惑。
當我談論“瞬間”時,我指的是可以用來識別什么時候發(fā)生了什么的概念。(這可能發(fā)生在將來,但最容易從過去的事情來考慮。)它獨立于時區(qū)和日歷系統(tǒng),因此多個使用“本地”時間表示的人可以用不同的方式談論它。
讓我們用一個非常具體的例子來說明發(fā)生在不使用我們熟悉的時區(qū)的地方的事情:尼爾·阿姆斯特朗在月球上行走。月球行走開始于一個特定的時刻——如果來自世界各地的多個人同時觀看,他們會(幾乎)同時說“我現(xiàn)在可以看到它正在發(fā)生”。
如果你在休斯頓的任務控制中心觀看,你可能會想到那一刻是“1969年7月20日,CDT晚上9:56:20”。如果你在倫敦觀看,你可能會想到那一刻是“1969年7月21日,英國夏令時凌晨3:26:20”。如果你在利雅得觀看,你可能會認為那一刻是“1389年7月7日上午5:56:20(+03)”(使用《古拉經(jīng)》日歷)。盡管不同的觀察者會在他們的時鐘上看到不同的時間,甚至不同的年份,但他們?nèi)匀粫紤]同一時刻。他們只是在應用不同的時區(qū)和日歷系統(tǒng),將即時轉(zhuǎn)換為更人性化的概念。
那么,計算機如何表示實例呢?它們通常在一個特定的瞬間之前或之后存儲一定量的時間,而這個瞬間實際上是一個原點。許多系統(tǒng)使用Unix紀元,這是格里高歷中以UTC表示的1970年1月1日開始的午夜。這并不意味著紀元本質(zhì)上是“在”UTC中的——Unix紀元同樣可以定義為“1969年12月31日紐約下午7點的那一刻”。
Date類使用“自Unix紀元以來的毫秒數(shù)”——這是getTime()返回的值,由Date(long)構造函數(shù)或setTime()方法設置。由于月球行走發(fā)生在Unix紀元之前,因此該值為負值:實際上是-14159020000。
為了演示日期如何與系統(tǒng)時區(qū)交互,讓我們展示前面提到的三個時區(qū)–休斯頓(美國/芝加哥)、倫敦(歐洲/倫敦)和利雅得(亞洲/利雅得)。當我們從歷元毫秒值構建日期時,系統(tǒng)時區(qū)是什么并不重要,這根本不取決于本地時區(qū)。但如果我們使用Date.toString(),它轉(zhuǎn)換為當前默認時區(qū)以顯示結(jié)果。更改默認時區(qū)根本不會更改日期值。對象的內(nèi)部狀態(tài)完全相同。它仍然表示相同的瞬間,但toString()、getMonth()和getDate()等方法將受到影響。
下面的示例代碼顯示:
import java.util.Date;
import java.util.TimeZone;
public class Test {
public static void main(String[] args) {
// The default time zone makes no difference when constructing
// a Date from a milliseconds-since-Unix-epoch value
Date date = new Date(-14159020000L);
// Display the instant in three different time zones
TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago"));
System.out.println(date);
TimeZone.setDefault(TimeZone.getTimeZone("Europe/London"));
System.out.println(date);
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Riyadh"));
System.out.println(date);
// Prove that the instant hasn't changed...
System.out.println(date.getTime());
}
}輸出如下:
Sun Jul 20 21:56:20 CDT 1969
Mon Jul 21 03:56:20 GMT 1969
Mon Jul 21 05:56:20 AST 1969
-14159020000
這里的輸出中的“GMT”和“AST”縮寫非常不幸——java.util.TimeZone并非在所有情況下都具有1970年之前值的正確名稱。不過時機已經(jīng)成熟。
常見問題
如何將Date日期轉(zhuǎn)換為其他時區(qū)?
你沒有——因為約會沒有時區(qū)。這是一個瞬間。不要被toString()的輸出所愚弄。這會顯示默認時區(qū)中的瞬間。這不是值的一部分。
如果代碼以日期作為輸入,則已經(jīng)發(fā)生了從“本地時區(qū)”到即時的任何轉(zhuǎn)換。(希望操作正確……)
如果您開始編寫一個帶有這樣簽名的方法,那么您并沒有幫助自己:
// A method like this is always wrong Date convertTimeZone(Date input, TimeZone fromZone, TimeZone toZone)
如何將Date日期轉(zhuǎn)換為其他格式?
你沒有——因為日期沒有格式。不要被toString()的輸出所愚弄。始終使用相同的格式,如文檔所述。要以特定方式格式化日期,請使用合適的日期格式(可能是SimpleDataFormat)——記住將時區(qū)設置為適合您使用的適當區(qū)域。
到此這篇關于深入了解Java.Util.Date詳情的文章就介紹到這了,更多相關Java.Util.Date 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
java+jdbc+mysql+socket搭建局域網(wǎng)聊天室
這篇文章主要為大家詳細介紹了java+jdbc+mysql+socket搭建局域網(wǎng)聊天室,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-01-01
Spring?中使用?Validation?注解校驗參數(shù)的方法
本文介紹了如何在Spring中使用Validation注解進行參數(shù)校驗,包括引入依賴、簡單示例、常見校驗注解分類與說明、分組校驗和自定義校驗,通過這些方法,可以方便地對Controller、Service等層面的參數(shù)進行校驗,確保數(shù)據(jù)的合法性和一致性,感興趣的朋友跟隨小編一起看看吧2024-11-11

