DateFormat

提供轉換Date輸出格式或將Date String轉回Date的功能。

SimpleDateFormat是最常使用的DateFormat子類別。我們以一個格式轉換的範例做說明:將2012-04-21T14:08:44.801Z格式轉為UTC+8時區並以yyyy-MM-dd HH:mm:ss表示。
2012-04-21T14:08:44.801Z是RFC3999Date的規格,Z是UTC+0的意思,我們可以使用yyyy-MM-dd'T'HH:mm:ss.SSS'Z'來表示此字串格式(並非所有RFC3999Date格式通吃,如果要通吃可參考Resource連結的做法)。其中T與Z使用單引號(')括起,以避免被DateFormat誤判。

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
df.setTimeZone(TimeZone.getTimeZone("UTC")); // or set GMT
Date date = df.parse("2012-04-21T14:08:44.801Z");

上述程式碼產生的日期輸出為Sat Apr 21 22:08:44 CST 2012。假如沒做setTimeZone,SimpleDateFormat預設會使用你機器上所設定的TimeZone,而從這時間轉成另一個TimeZone時間就會出問題(並非由UTC轉到UTC+8,而是Default TimeZone轉到UTC+8)。而TimeZone的部分可參考以下範例輸出對應,UTC與GMT時間差不了多一般都會被認為是一樣的時間,但TimeZone的getTimeZone只能認得UTC、*GMT*、GMT+Offset與時區名稱,如果輸入它不認得的名稱就會轉為GMT的TimeZone。

System.out.println(TimeZone.getTimeZone("UTC"));
>sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
 
System.out.println(TimeZone.getTimeZone("UTC+8"));
>sun.util.calendar.ZoneInfo[id="GMT",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
 
System.out.println(TimeZone.getTimeZone("ss"));
>sun.util.calendar.ZoneInfo[id="GMT",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
 
System.out.println(TimeZone.getTimeZone("GMT+8"));
>sun.util.calendar.ZoneInfo[id="GMT+08:00",offset=28800000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
 
System.out.println(TimeZone.getTimeZone("GMT+8:01"));
>sun.util.calendar.ZoneInfo[id="GMT+08:01",offset=28860000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
 
System.out.println(TimeZone.getTimeZone("GMT+8.1"));
>sun.util.calendar.ZoneInfo[id="GMT",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
 
System.out.println(TimeZone.getTimeZone("America/Los_Angeles"));
>sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]]

因此如果我們要將某個時間轉成另外一個格式與時區,可以用下面這個做法:

df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("GMT+08:00"));
System.out.println(df.format(date));

總結一下:

  • 使用DateFormat轉換時區時間時,必須注意source所要表達的時區為何,這樣parse後format才不會出問題。我想假如是一個多國使用的軟體,存到資料庫的時間應該會存GMT時區吧?
  • TimeZone.getTimeZone操作以GMT為主較佳,如果有明確的地區當然更好,畢竟GMT+8的國家也不少。
  • 格式的詳細對照可以直接參考javadoc,我是每次寫每次查。

我遇到有問題的格式是yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z',這是使用svn info -xml所產生出來的date格式。但我在使用parse method後,會將SSSSSS的時間進位過去,這裡是我還不解的地方。畢竟S代表毫秒,1000毫秒為1秒,六個S不曉得是表達什麼?