說起java中的時間,大家或許都很熟悉,朗朗上口的Date、Calendar、SimpleDateFormat等。但是大家對他們的認識真的很深刻嗎?今天我要想大家說的是TimeZone,即時區。
經常有人發現時間不對,比如相差8個小時等等,其真實原因便是TimeZone。只有正確合理的運用TimeZone,才能保證系統時間無論何時都是準確的。
影響TimeZone的因素:
1. 作業系統的時區設定。
2. 資料轉送時時區設定。
第一個原因其實是根本原因,當資料在不同作業系統間流轉時,就有可能因為作業系統的差異造成時間偏差,而JVM預設情況下擷取的就是作業系統的時區設定。因此在項目中最好事先設定好時區,例如:
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
那麼一旦時區設定不同導致時間有偏差怎麼辦?如何轉化呢?
● 用SimpleDateFormat的話,如下:
public static void main(String[] args) {Date date = new Date(1359641834000L);// 2013-1-31 22:17:14String dateStr = "2013-1-31 22:17:14";SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));try {Date dateTmp = dateFormat.parse(dateStr);System.out.println(dateTmp);} catch (ParseException e) {e.printStackTrace();}String dateStrTmp = dateFormat.format(date);System.out.println(dateStrTmp);}
運行結果:
Fri Feb 01 06:17:14 CST 20132013-01-31 14:17:14
我們發現同一時間,字串和日期運行出來的結果並不相同,那麼我們應該怎麼理解呢?一切都要以當前作業系統的時間為基準。我的作業系統是"Asia/Shanghai",即GMT+8的北京時間,那麼執行日期轉字串的format方法時,由於日期產生時預設是作業系統時區,因此2013-1-31 22:17:14是北京時間,那麼推算到GMT時區,自然是要減8個小時的;而執行字串轉日期的parse方法時,由於字串本身沒有時區的概念,因此2013-1-31 22:17:14就是指GMT(UTC)時間【ps:所有字串都看做是GMT時間】,那麼當轉化為日期時要加上預設時區,即"Asia/Shanghai",因此要加上8個小時。
● 用Calendar的話,如下:
public static void main(String[] args) {Date date = new Date(1359641834000L);// 2013-1-31 22:17:14System.out.println(date);Calendar calendar = Calendar.getInstance();calendar.setTimeZone(TimeZone.getTimeZone("GMT"));// 或者可以 Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));calendar.setTime(date);System.out.println(calendar.get(Calendar.HOUR_OF_DAY) + ":" + calendar.get(Calendar.MINUTE));}
運行結果:
Thu Jan 31 22:17:14 CST 201314:17
Calendar不涉及到日期與字串的轉化,因此不像SimpleDateFormat那麼複雜,與日期轉字串的思路類似。但是需要注意的是,設定完時區後,我們不能用calendar.getTime()來直接擷取Date日期,因此此時的日期與一開始setTime時是相同值,要想擷取某時區的時間,正確的做法是用calendar.get()方法,那麼我們怎麼獲得Date類型的日期呢?
正確的做法如下:
public static void main(String[] args) {Date date = new Date(1359641834000L);System.out.println(date);Calendar calendar = Calendar.getInstance();calendar.setTimeZone(TimeZone.getTimeZone("GMT"));// 或者可以 Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));calendar.setTime(date);Calendar calendar2 = Calendar.getInstance();calendar2.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), calendar.get(Calendar.SECOND));System.out.println(calendar2.getTime());}
運行結果:
Thu Jan 31 22:17:14 CST 2013Thu Jan 31 14:17:14 CST 2013
● 完美通用轉換方法
其實上面兩個轉換方法都要受到作業系統的時區設定影響,如果軟體在不同作業系統運行,仍然會有時間誤差,那麼怎麼才能統一呢?
public static void main(String[] args) {Date date = new Date(1359641834000L);System.out.println(date);date = changeTimeZone(date, TimeZone.getTimeZone("Asia/Shanghai"), TimeZone.getTimeZone("GMT"));System.out.println(date);}/** * 擷取更改時區後的日期 * @param date 日期 * @param oldZone 舊時區對象 * @param newZone 新時區對象 * @return 日期 */public static Date changeTimeZone(Date date, TimeZone oldZone, TimeZone newZone) {Date dateTmp = null;if (date != null) {int timeOffset = oldZone.getRawOffset() - newZone.getRawOffset();dateTmp = new Date(date.getTime() - timeOffset);}return dateTmp;}
運行結果:
Thu Jan 31 22:17:14 CST 2013Thu Jan 31 14:17:14 CST 2013
通過以上可以看出時區確實有不少需要我們注意和專研的地方,其實這並不是什麼高深的東西,也是java日期裡的基礎,我認為盲目學習各種開源架構並不能成為真正的高手,架構也是基於jdk的基礎上開發而來的,不懂jdk的基本知識,想真正提高到架構師的層級是非常苦難的,因此基礎很重要,掌握jdk基本功確實是成為“大俠”的前提條件,共同努力吧!