Java中的Date和時區轉換


1.Date中保存的是什么
在java中,只要我們執行
Date date = new Date();
就可以得到當前時間。如:
[java] view plain copy
 
  1. Date date = new Date();  
  2. System.out.println(date);  
輸出結果是:
Thu Aug 24 10:15:29 CST 2017
也就是我執行上述代碼的時刻:2017年8月24日10點15分29秒。是不是Date對象里存了年月日時分秒呢?不是的,Date對象里存的只是一個long型的變量,其值為自1970年1月1日0點至Date對象所記錄時刻經過的毫秒數,調用Date對象getTime()方法就可以返回這個毫秒數,如下代碼:
[java] view plain copy
 
  1. Date date = new Date();  
  2. System.out.println(date + ", " + date.getTime());  
輸出如下:
Thu Aug 24 10:48:05 CST 2017, 1503542885955
即上述程序執行的時刻是2017年8月24日10點48分05秒,該時刻距離1970年1月1日0點經過了1503542885955毫秒。反過來說,輸出的年月日時分秒其實是根據這個毫秒數來反算出來的。
 
2.時區
全球分為24個時區,相鄰時區時間相差1個小時。比如北京處於東八時區,東京處於東九時區,北京時間比東京時間晚1個小時,而英國倫敦時間比北京晚7個小時(英國采用夏令時時,8月英國處於夏令時)。比如此刻北京時間是2017年8月24日11:17:10,則東京時間是2017年8月24日12:17:10,倫敦時間是2017年8月24日4:17:10。
 
既然Date里存放的是當前時刻距1970年1月1日0點時刻的毫秒數,如果此刻在倫敦、北京、東京有三個程序員同時執行如下語句:
[java] view plain copy
 
  1. Date date = new Date();  
那這三個date對象里存的毫秒數是相同的嗎?還是北京的比東京的小3600000(北京時間比東京時間晚1小時,1小時為3600秒即3600000毫秒)?答案是,這3個Date里的毫秒數是完全一樣的。確切的說,Date對象里存的是自格林威治時間( GMT)1970年1月1日0點至Date對象所表示時刻所經過的毫秒數。所以,如果某一時刻遍布於世界各地的程序員同時執行new Date語句,這些Date對象所存的毫秒數是完全一樣的。也就是說,Date里存放的毫秒數是與時區無關的。
 
繼續上述例子,如果上述3個程序員調用那一刻的時間是北京時間2017年8月24日11:17:10,他們繼續調用
[java] view plain copy
 
  1. System.out.println(date);  
那么北京的程序員將會打印出2017年8月24日11:17:10,而東京的程序員會打印出2017年8月24日12:17:10,倫敦的程序員會打印出2017年8月24日4:17:10。既然Date對象只存了一個毫秒數,為什么這3個毫秒數完全相同的Date對象,可以打印出不同的時間呢?這是因為Sysytem.out.println函數在打印時間時,會取操作系統當前所設置的時區,然后根據這個時區將同毫秒數解釋成該時區的時間。當然我們也可以手動設置時區,以將同一個Date對象按不同的時區輸出。可以做如下實驗驗證:
[java] view plain copy
 
  1. Date date = new Date(1503544630000L);  // 對應的北京時間是2017-08-24 11:17:10  
  2.   
  3. SimpleDateFormat bjSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");     // 北京  
  4. bjSdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));  // 設置北京時區  
  5.   
  6. SimpleDateFormat tokyoSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  // 東京  
  7. tokyoSdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));  // 設置東京時區  
  8.   
  9. SimpleDateFormat londonSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 倫敦  
  10. londonSdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));  // 設置倫敦時區  
  11.   
  12. System.out.println("毫秒數:" + date.getTime() + ", 北京時間:" + bjSdf.format(date));  
  13. System.out.println("毫秒數:" + date.getTime() + ", 東京時間:" + tokyoSdf.format(date));  
  14. System.out.println("毫秒數:" + date.getTime() + ", 倫敦時間:" + londonSdf.format(date));  
輸出為:
毫秒數:1503544630000, 北京時間:2017-08-24 11:17:10
毫秒數:1503544630000, 東京時間:2017-08-24 12:17:10
毫秒數:1503544630000, 倫敦時間:2017-08-24 04:17:10
 
可以看出,同一個Date對象,按不同的時區來格式化,將得到不同時區的時間。由此可見,Date對象里保存的毫秒數和具體輸出的時間(即年月日時分秒)是模型和視圖的關系,而時區(即Timezone)則決定了將同一個模型展示成什么樣的視圖。
 
3.從字符串中讀取時間
有時我們會遇到從一個字符串中讀取時間的要求,即從字符串中解析時間並得到一個Date對象,比如將"2017-8-24 11:17:10"解析為一個Date對象。現在問題來了,這個時間到底指的是北京時間的2017年8月24日11:17:10,還是東京時間的2017年8月24日11:17:10?如果指的是北京時間,那么這個時間對應的東京時間2017年8月24日12:17:10;如果指的是東京時間,那么這個時間對應的北京時間就是2017年8月24日10:17:10。因此,只說年月日時分秒而不說是哪個時區的,是有歧義的,沒有歧義的做法是,給出一個時間字符串,同時指明這是哪個時區的時間。
從字符串中解析時間的正確作法是:指定時區來解析。示例如下:
[java] view plain copy
 
  1.   
[java] view plain copy
 
  1. String timeStr = "2017-8-24 11:17:10"; // 字面時間  
  2. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
  3. sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); // 設置北京時區  
  4. Date d = sdf.parse(timeStr);  
  5. System.out.println(sdf.format(d) + ", " + d.getTime());  
 
           
 
          
輸出為:
2017-08-24 11:17:10, 1503544630000,
 
將一個時間字符串按不同時區來解釋,得到的Date對象的值是不同的。驗證如下:
[java] view plain copy
 
  1. String timeStr = "2017-8-24 11:17:10"; // 字面時間  
  2. SimpleDateFormat bjSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
  3. bjSdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));  
  4. Date bjDate = bjSdf.parse(timeStr);  // 解析  
  5. System.out.println("字面時間: " + timeStr +",按北京時間來解釋:" + bjSdf.format(bjDate) + ", " + bjDate.getTime());  
  6.   
  7. SimpleDateFormat tokyoSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  // 東京  
  8. tokyoSdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));  // 設置東京時區  
  9. Date tokyoDate = tokyoSdf.parse(timeStr); // 解析  
  10. System.out.println("字面時間: " + timeStr +",按東京時間來解釋:"  + tokyoSdf.format(tokyoDate) + ", " + tokyoDate.getTime());  
輸出為:
字面時間: 2017-8-24 11:17:10,按北京時間來解釋:2017-08-24 11:17:10, 1503544630000
字面時間: 2017-8-24 11:17:10,按東京時間來解釋:2017-08-24 11:17:10, 1503541030000
可以看出,對於"2017-8-24 11:17:10"這個字符串,按北京時間來解釋得到Date對象的毫秒數是
1503544630000;而按東京時間來解釋得到的毫秒數是1503541030000,前者正好比后者大於3600000毫秒即1個小時,正好是北京時間和東京時間的時差。這很好理解,北京時間2017-08-24 11:17:10對應的毫秒數是1503544630000,而東京時間2017-08-24 11:17:10對應的北京時間其實是2017-08-24 10:17:10(因為北京時間比東京時間晚1個小時),北京時間2017-08-24 10:17:10自然比北京時間2017-08-24 11:17:10少3600000毫秒。
 
4.將字符串表示的時間轉換成另一個時區的時間字符串
綜合以上分析,如果給定一個時間字符串,並告訴你這是某個時區的時間,要將它轉換為另一個時區的時間並輸出,正確的做法是:
1.將字符串按原時區轉換成Date對象;
2.將Date對象格式化成目標時區的時間。
比如,將北京時間"2017-8-24 11:17:10"輸出成東京時間,代碼為:
[java] view plain copy
 
  1. String timeStr = "2017-8-24 11:17:10"; // 字面時間  
  2. SimpleDateFormat bjSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
  3. bjSdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));  
  4. Date date = bjSdf.parse(timeStr);  // 將字符串時間按北京時間解析成Date對象  
  5.   
  6. SimpleDateFormat tokyoSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  // 東京  
  7. tokyoSdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));  // 設置東京時區  
  8. System.out.println("北京時間: " + timeStr +"對應的東京時間為:"  + tokyoSdf.format(date));  
輸出為:
北京時間:2017-8-24 11:17:10對應的東京時間為:2017-08-24 12:17:10
版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/halfclear/article/details/77573956


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM