最近(終於)在測 gwt-jackson,負責在 server side 噴 JSON 的是 Gson,然後測到日期(java.util.Date
)的時候炸了一輪,所以來碎念一下留個紀念… XD
一開始以為是 gwt-jackson 炸掉,畢竟 GSON 資格老關係好(?),GWT 現在還有多少人在用都是個問題 lol。但是狗了一圈沒發現啥災情,事情開始有點詭異…
那找「gson date」試試看… WTF?GSON 預設的日期格式會隨平台不同而變?這就別提什麼 W3C 之類的標準了,根本亂搞一通嘛… =="
不過至少有解,就是可以用 new GsonBuilder().setDateFormat()
來設定 format 然後用這個 builder 來建立 Gson
instance。
那麼,什麼是 JSON 標準定義的日期格式呢?根據這個 stackoverflow 的說法,JSON 根本沒做出定義… =="
好吧,至少 JS / W3C 貌似有,就是 ISO-8601。
因為懶得查,所以直接狗「java dateformat 8601」,我的搜尋結果第一條是 stackoverflow,不過那是要把字串還原回 Date
,不太對題。第二條跟第三條(居然)是簡體中文,都是對岸的 CSDN。
先說第三條,文章裡頭給的 pattern 是 yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
,hmmm… 看起來跟前面 stackoverflow 附的範例一樣,丟下去跑也能正常 parse,太好了可以收工了… 才怪… 得到時間不對,整整多了 8 小時。WTF?時區問題?
算啦算啦… 去測第二條吧,直接拿文章內說可行的 yyyy-MM-dd'T'HH:mm:ss:SSSZZ
來試試看… 連 parse 都過不了?WTF?等等,為什麼反覆測試下發現有時候會 parse 過、而且值也正確?但有時候卻又 parse 不過?幹這是七月半提前報到嗎?
鬼打牆了 n 分鐘之後,終於發現… 測試會過的時候是測完第三條之後把 Z 前後的單引號拔掉,而測試不過的時候是直接複製第二條的文字…
對,X 他 X 的第二個給的 pattern 根本有問題,按照 ISO-8601 的規格,在 sec 跟 ms 中間應該是「.」而不是「:」。肉眼不仔細比對根本很難發現… Orz
到了這個時候,真的是被嚇到了,乖乖回頭看文件。在 Java API 的定義當中,「X」跟「Z」都表示時區,「X」是 ISO-8601 格式、「Z」是 RFC-822 格式(不過目前看不出差異)。ISO-8601 要求日期與時間之間以一個寫死的大寫「T」連結,寫成 Java 的 pattern 就要前後加上單引號。所以第三條 pattern 尾巴的「Z」是寫死不變的。那,為什麼 parse 會過呢?
在 ISO-8601 當中規定,如果時區剛好是 UTC(零時區)就顯示 Z,所以得到的是合法的字串,但是除非人在 UTC 不然解出來的實際 Date
就會有時差問題… Orz
心得與結論: