最近在开发中遇到一个非常罕见的问题,就是centos测试服务器上的时间虽然正确,但是安装在上面的Tomacat7.x的时间时区出现错误。
我的程序代码中,恰好使用了对时间查询的sql语句,例如
select <cols> from table where sendtime <= #{nowtime} and deadlinetime >= #{nowtime}
此时执行远程单步调试,发现代码中new Date()取得的当前时间nowtime,比正确的时间晚13个小时,造成查询结果错误,难道取当前时间还会出错?于是改用
Calendar calendar = Calendar.getInstance();
Date nowDate = calendar.getTime();
仍然不能获得正确的当前时间。这是怎么回事,好长时间让我一头雾水。
在网上搜索了一下通过代码解决的方案,有些文章给出了在代码中设置时区的办法,类似下面:
//更改当前时区为东八区GMT+8,即北京时间。
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
这样的话,通过new Date()或者calendar.getTime()可以取得当前正确时间了,但是又出现了新的问题,mysql数据库里数据的时间字段的时间发生了改变,全部自动加了13个小时!
具体就是,用客户端软件连接到mysql,执行select <cols> from table order by sendtime desc类似的语句,看到sendtime,deadlinetime等字段的值没有变化,但是远程单步调试时,查看执行上面sql语句取出的结果集列表里的时间,则全部自动往后推了13个小时,怎么会这样!前面忘记说了,时间字段都是timestamp型的字段。
看来使用代码设置时区,会对数据库的timestamp时间类型的字段产生影响。
至此,几乎一筹莫展,无计可施了。
突然,眼前灵光一闪,有了一个突破口,想起这几天观察这个Tomcat7.x的log日志文件的时间,也总是比当前正确时间晚13小时。是怎么发现这个问题的呢?在centos测试机上tail -f catalina.out文件时,发现实时打印的带时间信息的log语句,都比当前服务器时间晚13个小时。
笔者开发Java好多年,从未遇到过这种问题,以前遇到的,基本是服务器时区不正确,造成Tomcat等webserver时间跟着出错,这样至少服务器时区时间和webserver的时间还是一致的;而这次的情况,却是服务器时区,时间都正确,Tomcat容器的时间/时区却不正确。
至今尚不知如何造成这个错误的。因为我在自己账号的目录下直接wget一个tomcat7.x发行版并解压安装,并未出现这个问题,说明并不是tomcat7.x自身的问题。显然还是在对tomcat7.x的某些配置做了修订之后才会引发这个问题。
这下问题明了了,先把log日志的时间改正确再说!
为了解决此问题,google了一些文章,在${catalina_home}/bin/catalina.sh文件中的JAVA_OPTS启动参数中做了以下调整,
JAVA_OPTS="-server -Duser.timezone=GMT+08 -Xms1024m -Xmx1024m"
即增加了时区选项-Duser.timezone=GMT+08,重新启动Tomcat,log日志的时间正确了。
接着,改回原始的代码,注释TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));等语句,所有的时间和sql查询都正确了。
至此,问题彻底解决。