2014年2月9日 星期日

使用 Joda-Time 取得各時區的時間

話說前陣子研究 Joda-time 來取得各個時區的時間後,就把它應用在專案裡面。不過幾天專案發現出問題,讓我發現它的一個小小的問題。

問題的原因發生在把資料庫的時間轉換成我希望的時區,所以我寫了下面這個函數…
public Date getLocaleTime(Date date, String TimeZoneID) {
  DateTime time;
  if (date == null)
    time = new DateTime(DateTimeZone.forID(TimeZoneID));
  else 
    time = new DateTime(date, DateTimeZone.forID(TimeZoneID));
  return time.toLocalDateTime().toDate();
}

乍看之下沒有什麼問題,不過當選擇到某些特定的時區的時候就會出狀況,說 Joda-Time 不支援這個 TimeZone ID。

本來以為是抓到過時版本的 Joda-Time 函數庫,不過檢查之後顯示不是這麼一回事,是最新的版本。因此猜想可能它本身內建時區的清單,而不是抓 Java 原生函數庫所提供的,如果給予清單裡沒有的時區 ID,就會出現丢出例外,導致程式無法繼續下去。

由於這並不是「應該發生例外的地方」,所以必須找到不會出錯的程式寫法。時區清單上百筆資料,完全沒有興趣去查看 Joda-Time 原始碼來一一比對,更何況這種作法得面可能發生的人工錯誤,最最難查出來。所以得要想辦法用語言串接的作法完成。

想想既然我使用的是 Java 原生 TimeZone 類別所提供的時區清單,當然自己會能夠建立對應的物件。在花了許多時間查看 DateTime 類別有沒有任何可以給予 TimeZone 型別的建構式或靜態方法,也查了能産生 DateTime 的相關類別。在繞了一大圈之後,才發現原來 DateTimeZone 類別,除了可以支援輸入 TimeZone ID 字串的靜態方法,也有一個能直接放入 TimeZone 的,所以程式就被改寫成…
public Date getLocaleTime(Date date, String TimeZoneID) {
  DateTime time;
  if (date == null)
    time = new DateTime(DateTimeZone.forTimeZone(TimeZone.getTimeZone(TimeZoneID)));
  else 
    time = new DateTime(date, DateTimeZone.forTimeZone(TimeZone.getTimeZone(TimeZoneID)));
  return time.toLocalDateTime().toDate();
}

如此,本來不支援的 TimeZone ID 輸入時,也能夠正確的輸出該時區的時間。猜想可能是直接由 TimeZone 類別去抓取該時區和格林威冶時間的差距,所以和 TimeZone ID 的字串無關的關係。當然啦~~ 如果輸入的是 Java 原生不支援的,也還是有可能會出錯,不過因為可用清單被限制在 TimeZone 類別裡所提供,而不是由使用者自行輸入,所以可以暫時忽略這個問題。

沒有留言:

張貼留言