参考:https://blog.csdn.net/vae1314chuanchen/article/details/81838476
https://blog.csdn.net/sweatOtt/article/details/78111748
https://blog.csdn.net/weixin_42353194/article/details/90599215
一、修改MySql数据库的默认时区
MySql数据库创建后,默认的时区比东八区少了八个小时。如果Sql语句中使用到MySql的时间的话就会比正常时间少了八个小时。所以需要修改MySql的系统时区,使其显示的时间和我们现在的时间一致。
1)查看mysql系统时间
select now();
2)查看数据库时区
show variables like '%time_zone%';
3)设置时区更改为东八区
set global time_zone = '+8:00';
4)刷新权限
flush privileges;
5)退出后重新登录,即可。
6)修改my.cnf实现永久修改MySQL时区。
cd /etc
vim my.cnf
7)在mysqld下边的配置中添加一行:
default-time_zone = '+8:00'
8)然后重启mysql
service mysql restart
sudo systemctl restart mysqld
二、修改数据库的驱动
若时间还是不对,有可能是驱动的问题,检查下驱动信息,如果连接参数中的字段serverTimezone设置为UTC,将UTC更改为 Asia/Shanghai就可以了。
jdbc:mysql://127.0.0.1:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=Asia/Shanghai
三、查看和修改Linux服务器上的时区
对于部署在海外的Linux服务器来说,拿到的机器时区和本地并不一样,导致运行在上面的应用也面临时区问题,所以有必要修改Linux服务器上的时区。
1、查看服务器当前的时区
查看当前生效的时区,可以通过date -R命令来查看当前时间。
[webadmin@host ~]$ sudo date -R
Sun, 19 Aug 2018 15:18:38 +0800
注:+0800,即东8区。
2、设置时区
1)通过tzselect命令查看时区向导
tzselect命令看起来很像一个时区选择的工具,但并非如此。事实上tzselect仅仅是一个查看时区表示方式的『向导』程序而已。通过依次询问大洲→国家→城市,最后告诉你如何TZ变量的写法,比如北京时间是:Asia/Shanghai。
2)通过修改TZ变量**,直接修改时区信息
可以通过修改TZ变量,直接修改时区信息,比如:
[webadmin@host ~]$ sudo date -R
Sun, 19 Aug 2018 15:25:15 +0800
[webadmin@host ~]$ sudo export TZ='Asia/Shanghai'
[webadmin@host ~]$ sudo date -R
Sun, 19 Aug 2018 15:25:51 +0800
有Linux经验的小伙伴都知道,不写在文件里的设置更改很难生效一般是会话级的,重新登录会消失。所以,这样直接修改TZ的尿性绝对做不到持久化更改时区的。
正确的方式是到/etc/profile里(或用户的.profile或.bashrc文件),直接export TZ变量为要更改的时区(时区的名字可以用tzselect向导来确定)。
下面展示一波正确的做法:
1)代开文件.bash_profile
sudo vim ~/.bash_profile
2)在文末添加export TZ=‘Asia/Shanghai’
3)使配置生效
source ~/.bash_profile
3)重启相关service或者直接重启服务器
4)通过/etc/localtime文件修改时区
默认情况下情况下,TZ属性是空,这时候是靠**/etc/localtime文件来确定的时区。而此文件通常又是一个到/usr/share/zoneinfo/下各种时区文件的软连接。通过修改/etc/localtime**指向的软连接,进而修改系统的时区。比如下面的方法,将localtime文件设置为了北京时间:
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
四、
默认情况下mysql的time_zone为SYSTEM,也就是mysql的时区和服务器的时区是一样的。一般服务器都是东八区。在使用mysql时,客户端所在的时区一般也是东八区。所以从mysql查询timestamp类型数据时一切正常。
现在如果我们的条件是这样的:
使用的jdbc url长这样jdbc:mysql://localhost:3306/table_name
客户端的时区为零时区
mysql的时区是东八区
上面几个条件如果满足了,这时候你从mysql查找timestamp的数据,拿到的timestamp值和数据库中的值是一样的,没有考虑时区的问题,所以事实上是多了8小时。
通过debug,发现jdbc的ConnectionImpl类中configureTimezone()配置time zone时有几个条件
String canonicalTimezone = getServerTimezone();
if ((getUseTimezone() || !getUseLegacyDatetimeCode()) && configuredTimeZoneOnServer != null) {
// user can override this with driver properties, so don't detect if that's the case
if (canonicalTimezone == null || StringUtils.isEmptyOrWhitespaceOnly(canonicalTimezone)) {
try {
canonicalTimezone = TimeUtil.getCanonicalTimezone(configuredTimeZoneOnServer, getExceptionInterceptor());
} catch (IllegalArgumentException iae) {
throw SQLError.createSQLException(iae.getMessage(), SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
}
}
}
if (canonicalTimezone != null && canonicalTimezone.length() > 0) {
this.serverTimezoneTZ = TimeZone.getTimeZone(canonicalTimezone);
...
getServerTimezone()方法拿到的值默认为null,getUseTimezone()和getUseLegacyDatetimeCode()方法得到的值分别是false和true,这样就导致了connector不会使用数据库的time zone。所以我们从数据库内读取timestamp数据,不做任何时区转化。
如果想要开启时区转换,需要将useTimezone设置为true, 即jdbc:mysql://localhost:3306/table_name?useTimezone=true
我们可以看mysql文档对useTimezone描述
useTimezone
Convert time/date types between client and server time zones (true/false, defaults to ‘false’)? This is part of the legacy date-time code, thus the property has an effect only when “useLegacyDatetimeCode=true.”
Default: false
将useTimezone设置为true后,还有一点很重要,如果mysql的time_zone为SYSTEM,连接数据库是会报错的,需要给定一个明确的时区。我们可以把数据库的time_zone设置为+08:00,这样timestamp的数据就会根据时区进行转换。 如果不想修改数据库的time_zone,可以在客户端进行设置,指定time_zone,jdbc:mysql://localhost:3306/table_name?useTimezone=true&serverTimezone=GMT%2B8,GMT%2B8表示东八区。
五、最后一种方法:
设置spring配置文件:
1、spring.datasource.url=jdbc:mysql://10.35.105.25:3306/database?characterEncoding=utf-8&serverTimezone=GMT%2B8
数据库配置后面加上&serverTimezone=GMT%2B8
2、spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
第一步为设置数据库时间为东八区(北京)时间,保证debug时候从数据库查出时间一致。第二步为返回给前端的时间格式和时区设定,保证前端页面显示时间和数据库一致。
总结:认真分析各个步骤:数据库,驱动,后端向前端返回的时区