2014年1月5日 星期日

使用 Joda-Time 轉換成不同時區的時間

Java 原生的 Date 類別,是我一直沒搞明白的東西之一。總是認為它應該是一個集取得、設定時間方法大成的類別,卻奇怪於它的設定方法又少又有一部分不建議使用。而後來發現另一個叫  Calendar 的類別反而有著比較完整的方法,不懂原來的設定者希望開發人員如何使用它們。

後來在一次的技術討論中,聽到 Joda-Time 這個函數庫,說是讓人更方便操作時間資料,接手開發相關公用函數的過程,慢慢抓到它一部分的用法,記錄在這個地方。

查了一下網路資料,發現「Joda」這個字和星際大戰的「尤逹大師」是同一個字,不過作者說,這個專案裡的 J 應該發和 Java 裡的 J 一樣,也因為唸法不同,所以只是一個作來簡化 Java 程式開發的東西,沒有能夠揮舞下光劍的本領(笑)。

我所要處理的公用程式,是把由資料庫取出的時間資料,轉換成使用者所設定時區的時間。排除「使用者」這個參數,也就是要把輸入的時間轉成指定時區的資料。

由資料庫取得的是 Java 原生的 Date 物件,但是它偏偏沒有設定時區的方法,頂多有一個取得和格林威治時間相差秒數的方法(getTimezoneOffset),不過也不被建議使用,說不準哪天 Java 改版的時候這個方法就不見了。

為了作一系列的技術測試,我寫了一個簡單的測試程式,由固定字串產生不變的時間來模擬由資料庫取得的資料,方便作後續的觀察。

SimpleDateFormat foramt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date;
try {
  date = foramt.parse("2013-12-26 18:48:24");
  System.out.println(date);
} catch (ParseException e) {
  e.printStackTrace();
}

輸出︰
Thu Dec 26 18:48:24 CST 2013
在年(2013)前的 CST 是 China Standard Time 的縮寫,也就是中原標準時間的意思。因為我沒有作什麼其它的設定,所以 Java 會抓我本機系統的時區設定。而我的目標是把時間的結果,轉換成快一個小時的日本時間,這樣比較好作觀察。

如果單純將 Date 轉換成 Joda-Time 的對應類別,再將之輸出的話會得到以下結果…
DateTime jDate = new DateTime(date);
System.out.println(jDate);
輸出︰
2013-12-26T18:48:24.000+08:00
雖然有些難閱讀,但是還能夠看得出來,它也是以中原標準時間(UTC+8)的方式來顯示。

再來,經過修改建構式的參數,設定成日本的時區(UTC+9),就能夠輸出成地區的時間。
DateTime jDate = new DateTime(date, DateTimeZone.forOffsetHours(9));
System.out.println(jDate);

輸出︰
2013-12-26T19:48:24.000+09:00
這樣時間就改變了,不過要去記得要轉換地區的時間差,還是有點麻煩。如果知道該地方的時區代號(在 Java 裡叫作 TimeZoneId),也可以作為參數達到一樣的效果。如下面的程式…
DateTime jDate = new DateTime(date, DateTimeZone.forID("Asia/Tokyo"));
System.out.println(jDate);

輸出︰
2013-12-26T19:48:24.000+09:00
因為原生的 Java 的 TimeZone 類別有提供 getAvailableIDs 方法可以取得所有支援的 TimeZoneId,並且有 getDisplayName(Locale locale) 方法,可以轉換成各語系的表示方法。表示可以把 TimeZoneId 作為使用者設定記錄字串在資料庫中,再轉換時間的時候再取出來作為參數。

最後,由於許多既有程式還是使用 Date 類別來輸出字串,可以使用 toLocalDateTime() 加上 toDate 來轉換。
DateTime jDate = new DateTime(date, DateTimeZone.forID("Asia/Tokyo"));
System.out.println(jDate.toLocalDateTime().toDate());


輸出︰
Thu Dec 26 19:48:24 CST 2013
這樣的輸出就比較順眼了,但是需要注意的是,雖然時間多了一個小時,但是它的時區卻還是中原標準時間。所以這個資料只能用在輸出,而不能儲存,否則資料可能就亂掉了。

po 文章的同時再去查了下官網的文章,發現 Joda-Time 是一個滿完整函數庫,除了支援 JSP 標籤、Hibernate 框架,本身也有自己的輸出字串的方法,不過我還沒研究到,也許會作為另一篇分享的主題。

沒有留言:

張貼留言