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 |