背景
springboot项目国际化中,会遇到用户选择的时间和最终存到数据库的时间不一致,可能就是项目开发和部署时的时区没有处理好,导致时间转换出现了问题。
先了解时区都有哪些:
1.GMT:Greenwich Mean Time
格林威治标准时间 ; 英国伦敦格林威治定为0°经线开始的地方,地球每15°经度 被分为一个时区,共分为24个时区,相邻时区相差一小时;例: 中国北京位于东八区,GMT时间比北京时间慢8小时。
2.UTC: Coordinated Universal Time
世界协调时间;经严谨计算得到的时间,精确到秒,误差在0.9s以内, 是比GMT更为精确的世界时间
夏季节约时间,即夏令时;是为了利用夏天充足的光照而将时间调早一个小时,北美、欧洲的许多国家实行夏令时;
分析
画出用户时间数据的流转过程,如图
存在时区的几个存储地点:客户端,服务器,JVM。Mysql
流程:用户的浏览器根据客户端时区,获取当前时间---》把时间参数传给服务器--》jvm根据设置选择服务器的当前时区或者自己设置的时区---》把时间存入mysql,mysql安装时有自己的时区
需求:需要时间在传入和取出来的时候,保证一致
解决办法:那就需要保证不同时区之间可以来回转换或者时区都一致不进行转换。
解决过程
1.客户端
这个是用户的电脑,我们不能要求用户使用什么时区,所以这个无法修改,用户可能使用各种时区。这个是时间变化的原因,也是导致不统一的根本因素。
2.服务器和JVM
服务器这里有两种方式
(1)JVM在服务器上,如果JVM没有设置时区的话,就会默认选择当前服务器的时区。
(2)设置JVM的时区,这样就会屏蔽掉服务器的时区,服务器的时区不会影响JVM的时区,也就不会影响用户时间参数的流转,选择这个。
[原创]Java项目统一UTC时间方案
3.Mysql
查看时区:show variables
like
'%time_zone%'
;
设置mysql的时区:MySQL默认的时区是UTC时区
(1)永久的修改:修改mysql的配置文件my-default.ini,添加:default-time-zone=’+08:00’,重启mysql生效,注意一定要在 [mysqld] 之下加 ,否则会出现 unknown variable ‘default-time-zone=+8:00’
my-default.ini文件内:
[mysqld]
default-time-zone='+08:00'
(2)临时的修改:执行mysql命令 set global time_zone=’+08:00’,立即生效,重启mysql后失效
set time_zone = '+8:00';
set global time_zone='+08:00';
设置时区总结:客户端不设置,用户随意时区变化--》设置JVM的时区为UTC---》设置mysql的永久时区为UTC
代码解决过程
1.客户端选择本地时区的时间
2.前端组件判断转换为UTC时区的时间
3.前端传给后端的时候,后端使用@DateTimeFormat注解转换格式,但是这个不能处理时区
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
private Date date;
4.后端JVM设置为
@SpringBootApplication
public class Application {
@PostConstruct
void started() {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
5.代码连接数据库的url,其中useLegacyDatetimeCode
参数默认是true
,我们需要手动设置为false
,否则无效
spring.datasource.url=jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=utf-8&useLegacyDatetimeCode=false&serverTimezone=UTC
6.mysql设置存储时区为UTC
7.从数据库到服务器,服务器后端(前面的过程不会乱变了,只需要)返回给前端的时候使用@JsonFormat,固定时区
@JsonFormat(
pattern = "yyyy-MM-dd HH:mm:ss",
timezone = "GMT+8"
)
private Date date;