Java基礎系列-時間日期API
原創文章,轉載請標註出處:《Java基礎系-列時間日期API》
一、概述
Java提供了有關時間的類和API,可以很方便的處理日期時間。
JDK 1.8之前使用的是Date和Calendar,JDK 1.8之後使用DateTime,前者毛病較多,後者更加適用。
二、基礎知識
2.1 時區
我們都知道,地球是圓的,並且在不停的自轉與公轉,自轉一圈是為一天,公轉一圈是為一年。
我們這裡關注自轉的部分。
圓形的地球總是存在面向太陽的半球與背向太陽的半球,面向太陽的半球為白天,背向太陽的半球為黑夜,邊界區域為凌晨和傍晚。
那麼在這些處於地球不同位置的地區的時間也怎麼分配的呢?
如果我們規定一個統一的時間,讓全球共用。這樣的話,0點時分,全球將擁有各種不同的景象,有的在凌晨,有的在早晨,有的在中午,有的在下午,有的在晚上等等,這也無關大雅。
但是當一個人從一個地方到另外一個地方後,他自認為的時間與光景將不再對應,這就是時差。
舉個例子,比如規定中國晚上0點為統一的0點時間,而中國和美國都是在白天工作,晚上休息,但是中國是白天的時候,美國正好是晚上,一個人從中國到達美國之後,看到的就是人們在0點上班,12點休息,這與人的行為習慣相悖!
所以有了時區的概念,將全球以經線均分為24個時區,相鄰時區的時間相差一個小時,當你跨越時區時,只要將你的手錶調快或調慢一個小時即可,還是滿足你的0點休息,12點上班的行為習慣。
實際上我們並沒有絕對的使用標準的時區來劃分時間,比如中國,橫跨5個時區,為了國內的時間統一,我們規定統一使用北京時間為中國的時間。
2.2 格林威治時間
有了時區的概念,那麼就有一個標準時間的問題了,以哪個地方為標準來定義時間呢?
那就是格林威治時間了,即GMT(Greenwich Mean Time)。
GMT表示的是格林威治平時,是指位於英國倫敦郊區的皇家格林尼治天文臺當地的平太陽時,因為本初子午線被定義為通過那裡的經線。
自1924年2月5日開始,格林尼治天文臺負責每隔一小時向全世界發放調時資訊。國際天文學聯合會於1928年決定,將由格林威治平子夜起算的平太陽時作為世界時,也就是通常所說的格林威治時間。
比如中國北京位於東八區,所以北京時間即為GMT+8,即北京時間比格林威治平時快8個小時。
2.3 時間戳
時間戳是指格林威治時間1970年01月01日00時00分00秒起至現在的總秒數。
這個值是全球固定值,全球通用,雖然各地的時間不同,但是時間戳是一致的。
有了時間戳,我們就是實現不同地區時間的轉換。
三、Date/Calendar/SimpleDateFormat
3.1 Date
關於Date,請檢視java基礎系列--Date類
3.2 Calendar
關於Calendar,請檢視java基礎系列--Calendar類
3.3 SimpleDateFormat
SimpleDateFormat是JDK提供的用於實現Date與String之間相互轉換的工具類,成為時間格式化工具。
我們來看一下簡單的格式化方式:
public class SimpleDateFormatTest { public static void main(String[] args) throws ParseException { test(); } public static void test() throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 格式化-將Date格式化輸出 Date date = new Date(); System.out.println(sdf.format(date)); // 解析-將String解析為Date String dateStr = "2019-01-01 12:12:12"; System.out.println(sdf.parse(dateStr)); } }
執行結果為:
2019-02-20 18:01:30 Tue Jan 01 12:12:12 CST 2019
最後輸出了“Tue Jan 01 12:12:12 CST 2019”格式的字串是因為使用System.out.println()方式輸出自動呼叫了Date的toString方法。
上面的東西就是基礎,重點關注的是下面的內容。
SimpleDateFormat是非執行緒安全的類,如果將其作為共享變數使用,在多執行緒環境中將會發生執行緒安全問題。
下面是推薦的處理辦法:
- 作為區域性變數使用
- 加鎖
- 使用ThreadLocal,這也是阿里巴巴java手冊中推薦的方式。
public static ThreadLocal<SimpleDateFormat> sdfThreadLocal = new ThreadLocal<SimpleDateFormat>(){ @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } };
- 更徹底的方式是使用DateTimeFormatter來替換。
這裡只補充一點關於時區的內容:
Date其實儲存的就是時間戳,我們可以通過設定時區來獲取不同地點的當前時間。
public class DateTest { public static void main(String[] args) { Date date1 = new Date(0);// 格林威治1970年1月1日0點0分0秒 System.out.println("格林威治0時的時間戳:" + date1.getTime()); System.out.println("格林威治0時的中國時區時間:" + date1); Date date2 = new Date();// 當前時間戳 System.out.println("date2的時間戳:" + date2.getTime()); System.out.println("date2表示的中國時區時間:" + date2); TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));// 設定時區為美國洛杉磯時區 System.out.println("date2表示的美國洛杉磯時區時間:" + date2); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));// 設定為美國紐約時區 System.out.println("date2表示的美國紐約時區時間:" + sdf.format(date2)); } }
執行結果為:
格林威治0時的時間戳:0 格林威治0時的中國時區時間:Thu Jan 01 08:00:00 CST 1970 date2的時間戳:1550656106538 date2表示的中國時區時間:Wed Feb 20 17:48:26 CST 2019 date2表示的美國洛杉磯時區時間:Wed Feb 20 01:48:26 PST 2019 date2表示的美國紐約時區時間:2019-02-20 04:48:26
可見中國時區的時間確實是比格林威治時間快8個小時,而美國洛杉磯時區的時間則是比格林威治時間慢8個小時,美國紐約時區的時間又比洛杉磯快3個小時。
如果不指定時區,則自動獲取作業系統的預設時區。
參考: