https://4aiur.github.io/2018/03/26/gson-dateformat-pattern/java
線上的日誌裏報了一個JsonSyntaxException
的異常:git
1 |
Exception in thread "main" com.google.gson.JsonSyntaxException: 2018-03-26 22:22:35 |
RPC框架是hessian, 這個錯誤發生在調用hessian接口時, 本地一切正常, 放到線上就報錯.github
最後發現調用時反序列化時Gson是這樣實例化的web
1 |
Gson gson = new Gson() |
改成工廠模式構建出的Gson就行了json
1 |
Gson builderTime = (new GsonBuilder()).setDateFormat("yyyy-MM-dd HH:mm:ss").create(); |
實體類裏只有java.util.Date
類型, 按理說序列化以後應該是Mon Mar 26 21:17:43 CST 2018
纔對, 這個時間格式明顯是被格式化了,
因而發如今hessian的服務端, GsonBuilder
格式化了這個時間,windows
1 |
Gson gson = (new GsonBuilder()).setDateFormat("yyyy-MM-dd HH:mm:ss").create(); |
把實體類格式化成了這種樣子centos
{"name":"foo","startTime":"2018-03-26 21:17:43"}
而在另外一邊, 在hessian的客戶端, 是這樣反序列的:框架
1 |
Gson gson = new Gson(); |
在win10簡體中文版環境下一切正常, 結果到了線上CentOS環境下,
這樣Gson gson = new Gson()
獲得的gson不能正常的將yyyy-MM-dd HH:mm:ss
格式的時間轉換爲GMT格式.ui
根據報錯信息打開出錯的源頭com.google.gson.internal.bind.DateTypeAdapter.java
類中的deserializeToDate()
方法, 這個方法是這樣的google
1 |
private synchronized Date deserializeToDate(String json) { |
這是一個很暴力的適配器模式, localFormat, enUsFormat, ISO8601Utils挨個嘗試轉換,那麼這三個值具體是什麼呢, 打個斷點來看看:
首先是ISO8601,Google的大佬直接hard code 成Locale.US
.
這是個UTC時間, T標識是UTC時間,Z標識時區, 北京時間比UTC快的8個小時, 會被記做UTC+8, 這就是東八區的由來, 以下:
UTC例子
美國的時間會標記出上午和下午, 時間格式是MMM dd, yyyy hh:mm:ss a
, 例如Sep 16, 2015 10:34:23 AM
.
注意到這個java.text.DateFormat#getDateTimeInstance(int, int)
這個方法,
不一樣地區規定的經常使用日期格式是不同的, 查詢WIKI百科各地日期和時間表示法,得知這個日期格式是臺灣的經常使用日期格式,
問題它怎麼知道我是在美國仍是在中國臺灣, 看getDateTimeInstance
方法的源碼
getDateTimeInstance()
發現這個方法在Java7以後, 根據操做系統的語言, 判斷用戶所在的時區,
那如今將WIN10控制面板=>時鐘、語言和區域=>添加語言=>更改windows顯示語言爲英語-美國, 再來看localFormat變成了什麼:
us-localFormat
坑爹啊Gson, 使用locale
命令查一查線上CentOS7的語言環境
1 |
[root@VM_0_9_centos ~]# locale |
果真是英文環境, 這樣的話yyyy-MM-dd HH:mm:ss
,
既沒法被UTC時間yyyy-MM-dd'T'HH:mm:ss'Z'
適配,
沒法被美國默認時間MMM dd, yyyy hh:mm:ss a
適配, 最後拋出了JsonSyntaxException
.
改爲中文, 並重啓系統
1 |
// 查看系統擁有語言包 |
zh_CN.UTF-8是簡體中文,若是沒有zh_CN.UTF-8,就安裝語言包,若是存在能夠直接設置
1 |
// 安裝簡中語言包 |
永久修改系統語言
1 |
localectl set-locale LANG=zh_CN.UTF8 |