背景 公司各个项目组用的mysql 版本不一样,有的是5.x稳定守旧版,有的最近喜欢用8.x高级迎新版,结果出了问题。
现象,数据库中保存的时间与java读取的时间字段不一样。
最开始数据库mysql版本为5.7.28,驱动为5.1 反正5.x都没什么问题。
数据库时区为 show variables like '%zone%'
现在有人使用mysql 8.x的版本,项目中就使用8.x的驱动
导致的问题就是时间字段不一致!!而且读取的时候还出问题了。
Caused by: com.mysql.cj.exceptions.WrongArgumentException: HOUR_OF_DAY: 2 -> 3
举例 数据库为5.x版本,数据库存放数据
我使用5.x的驱动
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
得到结果:id=8637200,last_update_date2021-03-13 14:03:54.0
使用8.x的驱动
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
<!-- <version>5.1.49</version>-->
</dependency>
得到结果:id=8637200,last_update_date2021-03-14 04:03:54.0
相差时间有10个小时,其中有同事遇到过相差13个小时的,这种肯定就是时区问题了
java.sql.SQLException: HOUR_OF_DAY: 2 -> 3_-兰天白云-的博客-CSDN博客
解决办法分为几种
1. mysql-connector-java.jar版本6.x、8.x降级为5.1.x
2. 对于高版本jdbc,连接串强制指定时区参数:serverTimezone=GMT%2B8
这个第二点有人说serverTimezone=Asia/Shanghai。
3. 对于高版本jdbc,mysql数据库强制修改time_zone为“+8:00”,而非“SYSTEM
第一点 经过之前测试降级没有问题。我用5.1的驱动连接没问题。
第二点 那种才是正确的呢?
serverTimezone=Asia/Shanghai 的结果是正确的
id=8637200,last_update_date2021-03-13 14:03:54.0
serverTimezone=GMT%2B8 的结果也是正确的。
id=8637200,last_update_date2021-03-13 14:03:54.0
怪我经验太少 都是中国的。。但是一个是shanghai一个是2B8。。。差的太多了
//北京时间东八区
serverTimezone=GMT%2B8
//上海时间
serverTimezone=Asia/Shanghai
下面我来好好学习下时区,以及为什么会出现这个问题。
先学习下时区的基本信息UTC GMT EST CST 区别_cst est_天已青色等烟雨来的博客-CSDN博客
- GMT - (Greenwich Mean Time)的缩写,指的是皇家格林威治天文台的标准时间,称作格林威治时间,因为本初子午线通过此地区,因此也称为世界标准时间。然而地球的自转不是完全规律的,而且正逐渐减慢,因此自1924年开始,格林威治时间(GMT)已经不再被视为标准时间,取而代之的是"世界协调时间" (UTC: Coordinated Universal Time)
- UTC - 协调世界时(Coordinated Universal Time)是最主要的世界时间标准,其以原子时秒长为基础,在时刻上尽量接近于格林尼治标准时间。UTC 是一个标准,而不是一个时区
- CST - 北京时间,China Standard Time,中国标准时间,是中国的标准时间。在时区划分上,属东八区,比协调世界时早8小时,记为UTC+8
- EST - 和CST一样,是众多时区中的一种时区。
缩写 | 全称 | 中文名称 | 类型 | UTC 偏移量 |
---|---|---|---|---|
+03 | +03 | - | UTC +03:00 | |
+04 | +04 | - | UTC +04:00 | |
+05 | +05 | - | UTC +05:00 | |
+0530 | +0530 | - | UTC +05:30 | |
+06 | +06 | - | UTC +06:00 | |
ACDT | Australian Central Daylight Time | 澳大利亚中部夏令时 | 夏令时 | UTC +10:30 |
ACST | Australian Central Standard Time | 澳大利亚中部标准时间 | - | UTC +09:30 |
ACT | Acre Time | 阿卡时间 | - | UTC -05:00 |
ACWST | Australian Central Western Standard Time | 澳大利亚中西部标准时间 | - | UTC +08:45 |
ADT | Atlantic Daylight Time | 大西洋夏令时间 | 夏令时 | UTC -03:00 |
AEDT | Australian Eastern Daylight Time | 澳大利亚东部夏令时 | 夏令时 | UTC +11:00 |
AEST | Australian Eastern Standard Time | 澳大利亚东部标准时间 | - | UTC +10:00 |
AFT | Afghanistan Time | 阿富汗时间 | - | UTC +04:30 |
AKDT | Alaska Daylight Time | 阿拉斯加夏令时 | 夏令时 | UTC -08:00 |
AKST | Alaska Standard Time | 阿拉斯加标准时间 | - | UTC -09:00 |
AMST | Amazon Summer Time | 亚马逊夏令时 | 夏令时 | UTC -03:00 |
AMT | Amazon Time | 亚马逊时间 | - | UTC -04:00 |
ART | Argentina Time | 阿根廷时间 | - | UTC -03:00 |
AST | Arabia Standard Time | 阿拉伯标准时间 | - | UTC +03:00 |
AST | Atlantic Standard Time | 大西洋标准时间 | - | UTC -04:00 |
AWST | Australian Western Standard Time | 澳大利亚西部标准时间 | - | UTC +08:00 |
AZOST | Azores Summer Time | 亚速尔群岛夏令时 | 夏令时 | UTC -00:00 |
AZOT | Azores Time | 亚速尔群岛时间 | - | UTC -01:00 |
BOT | Bolivia Time | 玻利维亚时间 | - | UTC -04:00 |
BRST | Brasília Summer Time | 巴西利亚夏令时 | 夏令时 | UTC -02:00 |
BRT | Brasília Time | 巴西利亚时间 | - | UTC -03:00 |
BST | British Summer Time | 英国夏令时间 | 夏令时 | UTC +01:00 |
BTT | Bhutan Time | 不丹时间 | - | UTC +06:00 |
CAT | Central Africa Time | 中非时间 | - | UTC +02:00 |
CDT | Central Daylight Time | 中部夏令时间 | 夏令时 | UTC -05:00 |
CDT | Cuba Daylight Time | 古巴夏令时 | 夏令时 | UTC -04:00 |
CEST | Central European Summer Time | 欧洲中部夏令时间 | 夏令时 | UTC +02:00 |
CET | Central European Time | 欧洲中部时间 | - | UTC +01:00 |
CHADT | Chatham Island Daylight Time | 查塔姆岛夏令时 | 夏令时 | UTC +13:45 |
CHAST | Chatham Island Standard Time | 查塔姆岛标准时间 | - | UTC +12:45 |
CHOST | Choibalsan Summer Time | 乔巴山夏令时 | 夏令时 | UTC +09:00 |
CHOT | Choibalsan Time | 乔巴山时间 | - | UTC +08:00 |
CHUT | Chuuk Time | 丘克时间 | - | UTC +10:00 |
CKT | Cook Island Time | 库克群岛时间 | - | UTC -10:00 |
CLST | Chile Summer Time | 智利夏令时 | 夏令时 | UTC -03:00 |
CLT | Chile Standard Time | 智利标准时间 | - | UTC -04:00 |
CST | Central Standard Time | 中部标准时间 | - | UTC -06:00 |
CST | China Standard Time | 中国标准时间 | - | UTC +08:00 |
CST | Cuba Standard Time | 古巴标准时间 | - | UTC -05:00 |
ChST | Chamorro Standard Time | 查莫罗标准时间 | - | UTC +10:00 |
EASST | Easter Island Summer Time | 复活岛夏令时 | 夏令时 | UTC -05:00 |
EAST | Easter Island Standard Time | 复活节岛标准时间 | - | UTC -06:00 |
EAT | Eastern Africa Time | 非洲东部时间 | - | UTC +03:00 |
ECT | Ecuador Time | 厄瓜多尔时间 | - | UTC -05:00 |
EDT | Eastern Daylight Time | 东部夏令时间 | 夏令时 | UTC -04:00 |
EEST | Eastern European Summer Time | 东欧夏令时 | 夏令时 | UTC +03:00 |
EET | Eastern European Time | 东欧时间 | - | UTC +02:00 |
EST | Eastern Standard Time | 东部标准时间 | - | UTC -05:00 |
FKST | Falkland Islands Summer Time | 福克兰群岛夏令时 | - | UTC -03:00 |
GFT | French Guiana Time | 法属圭亚那时间 | - | UTC -03:00 |
GILT | Gilbert Island Time | 吉尔伯特群岛时间 | - | UTC +12:00 |
GMT | Greenwich Mean Time | 格林威治标准时间 | - | UTC -00:00 |
GST | Gulf Standard Time | 海湾标准时间 | - | UTC +04:00 |
HKT | Hong Kong Time | 香港时间 | - | UTC +08:00 |
HST | Hawaii Standard Time | 夏威夷标准时间 | - | UTC -10:00 |
ICT | Indochina Time | 印度支那时间 | - | UTC +07:00 |
IDT | Israel Daylight Time | 以色列夏令时 | 夏令时 | UTC +03:00 |
IRDT | Iran Daylight Time | 伊朗夏令时 | 夏令时 | UTC +04:30 |
IRST | Iran Standard Time | 伊朗标准时间 | - | UTC +03:30 |
IST | India Standard Time | 印度标准时间 | - | UTC +05:30 |
IST | Irish Standard Time | 爱尔兰标准时间 | 夏令时 | UTC +01:00 |
IST | Israel Standard Time | 以色列标准时间 | - | UTC +02:00 |
JST | Japan Standard Time | 日本标准时间 | - | UTC +09:00 |
KOST | Kosrae Time | 科斯雷时间 | - | UTC +11:00 |
KST | Korea Standard Time | 韩国标准时间 | - | UTC +08:30 |
LINT | Line Islands Time | 莱恩群岛时间 | - | UTC +14:00 |
MDT | Mountain Daylight Time | 山区夏令时 | 夏令时 | UTC -06:00 |
MHT | Marshall Islands Time | 马绍尔群岛时间 | - | UTC +12:00 |
MSK | Moscow Standard Time | 莫斯科标准时间 | - | UTC +03:00 |
MST | Mountain Standard Time | 山地标准时间 | - | UTC -07:00 |
MYT | Malaysia Time | 马来西亚时间 | - | UTC +08:00 |
NDT | Newfoundland Daylight Time | 纽芬兰夏令时 | 夏令时 | UTC -02:30 |
NPT | Nepal Time | 尼泊尔时间 | - | UTC +05:45 |
NST | Newfoundland Standard Time | 纽芬兰标准时间 | - | UTC -03:30 |
NUT | Niue Time | 纽埃时间 | - | UTC -11:00 |
NZDT | New Zealand Daylight Time | 新西兰夏令时 | 夏令时 | UTC +13:00 |
NZST | New Zealand Standard Time | 新西兰标准时间 | - | UTC +12:00 |
PDT | Pacific Daylight Time | 太平洋夏令时 | 夏令时 | UTC -07:00 |
PET | Peru Time | 秘鲁时间 | - | UTC -05:00 |
PGT | Papua New Guinea Time | 巴布亚新几内亚时间 | - | UTC +10:00 |
PHT | Philippine Time | 菲律宾时间 | - | UTC +08:00 |
PKT | Pakistan Standard Time | 巴基斯坦标准时间 | - | UTC +05:00 |
PONT | Pohnpei Standard Time | 波纳佩标准时间 | - | UTC +11:00 |
PST | Pacific Standard Time | 太平洋标准时间 | - | UTC -08:00 |
SAST | South Africa Standard Time | 南非标准时间 | - | UTC +02:00 |
SBT | Solomon Islands Time | 所罗门群岛时间 | - | UTC +11:00 |
SGT | Singapore Time | 新加坡时间 | - | UTC +08:00 |
SRT | Suriname Time | 苏里南时间 | - | UTC -03:00 |
SST | Samoa Standard Time | 萨摩亚标准时间 | - | UTC -11:00 |
TAHT | Tahiti Time | 塔希提岛时间 | - | UTC -10:00 |
TLT | East Timor Time | 东帝汶时间 | - | UTC +09:00 |
TVT | Tuvalu Time | 图瓦卢时间 | - | UTC +12:00 |
ULAST | Ulaanbaatar Summer Time | 乌兰巴托夏令时 | 夏令时 | UTC +09:00 |
ULAT | Ulaanbaatar Time | 乌兰巴托时间 | - | UTC +08:00 |
UYST | Uruguay Summer Time | 乌拉圭夏令时 | 夏令时 | UTC -02:00 |
UYT | Uruguay Time | 乌拉圭时间 | - | UTC -03:00 |
VET | Venezuelan Standard Time | 委内瑞拉标准时间 | - | UTC -04:00 |
WAST | West Africa Summer Time | 西非夏令时 | 夏令时 | UTC +02:00 |
WAT | West Africa Time | 西非时间 | - | UTC +01:00 |
WEST | Western European Summer Time | 西欧夏令时间 | 夏令时 | UTC +01:00 |
WET | Western European Time | 西欧时间 | - | UTC -00:00 |
WIB | Western Indonesian Time | 印尼西部时间 | - | UTC +07:00 |
WIT | Eastern Indonesian Time | 印度尼西亚东部时间 | - | UTC +09:00 |
WITA | Central Indonesian Time | 印度尼西亚中部时间 | - | UTC +08:00 |
注意这里上面的有三个CST!!
说下时区的注意点。
在中国新疆哈密是东六区到北京是东八区,从西到东有2个小时的时差,
在美国从东向西分别为东部时间(EST)(西五区时间)、中部时间(CST)(西六区时间)、山地时间(MST)(西七区时间)、太平洋时间(西部时间)(PST)(西八区时间)、阿拉斯加时间(AKST)(西九区时间)和夏威夷时间(HST)(西十区时间)
但是这个时差在中国为啥不明显,因为在中国这个时间统一了,比如北京八点上班,此时按照时区时间新疆是6点,时间也差不了太多,所以可以看作中国无时差,无时区。
但是在美国不一样,时差由政府把握,也即是我们说的每到一个时区,你需要把手表时间快或慢一小时。
再补充学习下夏令时的概念。
夏令时_百度百科
注意对于夏令时各个国家也有不同的做法。
中国1992年起,夏令时暂停实行。
俄罗斯自从2011年3月27日开始永久使用夏令时,把时间拨快一小时,不再调回。
美国夏时制的实行与否,完全由各州、各县自行决定,不由联邦政府统一规定。目前美国绝大部分地区实行夏令时。
此时举个例子,
我们现在是东八区,美国华盛顿是西五区,此时时差应该是(东8-西5-中时区)=13个小时
因为有夏令时的存在,华盛顿西五区要快1小时,变成了西四区,所以现在的时差如下=12小时
此时回头看下我们数据 2021-03-13 14:03:54.0和2021-03-14 04:03:54.0 相差了10个小时好像和12/13对不上?接着学习。
夏令时:
由于美国有夏令时,CST非夏令时对应 UTC-06:00,夏令时对应 UTC-05:00 。
美国的夏令时,从每年3月第2个星期天凌晨开始,到每年11月第1个星期天凌晨结束。
以2020年为例: 3月第2个星期天为3月8号
夏令时开始时间调整前:2020年03月08日星期日 02:00:00,时间向前拨一小时.
调整后:2020年03月08日星期日 03:00:00
夏令时结束时间调整前:2020年11月01日星期日 02:00:00,时间往回拨一小时.
调整后:2020年11月01日星期日 01:00:00
这意味这:CST没有2020-03-08 02:00:00~2020-03-08 03:00:00 这个区间的时间。会有两个 2020-11-01 01:00:00~2020-11-01 02:00:00区间的时间
说实话这里我都有点乱了。
public static void main(String[] args) { Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("CST"), Locale.US); calendar.setLenient(false);//容错模式 例如分钟1000会进位到小时 //2020-03-08 01:02:00 calendar.set(2020, 2, 8, 1, 2, 0); Date date1 = new Date(calendar.getTimeInMillis()); String format = f1.format(date1); System.out.println("设置时间为 2020-03-08 01:02:00," + "CST时区时间为 " + format); //2020-03-08 01:02:00 非夏令时间,于北京时间相差14小时。 //2020-03-08 03:02:00 calendar.set(2020, 2, 8, 3, 2, 0); Date date3 = new Date(calendar.getTimeInMillis()); String format3 = f1.format(date3); System.out.println("设置时间为 2020-03-08 03:02:00," + "CST时区时间为 " + format3); //2020-03-08 03:02:00 夏令时间,于北京时间相差13小时。 //抛出 Exception: HOUR_OF_DAY: 2 -> 3 //2020-03-08 02:02:00 calendar.set(2020, 2, 8, 2, 2, 0); //抛出异常:java.lang.IllegalArgumentException: HOUR_OF_DAY: 2 -> 3 Date error = new Date(calendar.getTimeInMillis()); String format2 = f1.format(error); System.out.println("设置时间为 2020-03-08 03:02:00," + "CST时区时间为 " + format2); }
设置时间为 2020-03-08 01:02:00,CST时区时间为 2020-03-08 15:02:00
设置时间为 2020-03-08 03:02:00,CST时区时间为 2020-03-08 16:02:00
Exception in thread "main" java.lang.IllegalArgumentException: HOUR_OF_DAY: 2 -> 3
at java.util.GregorianCalendar.computeTime(GregorianCalendar.java:2829)
at java.util.Calendar.updateTime(Calendar.java:3393)
at java.util.Calendar.getTimeInMillis(Calendar.java:1782)
at com.chenchi.learning.java.calender.CalenderTest.main(CalenderTest.java:66)
这里有个问题 我在中国默认的timeZone为 Asia/Shanghai。
上面设置的CST是啥?
美国中部时间 Central Standard Time (USA) UTC-05:00 / UTC-06:00
澳大利亚中部时间 Central Standard Time (Australia) UTC+09:30 --这个上面又是 ACST
中国标准时间 China Standard Time UTC+08:00
古巴标准时间 Cuba Standard Time UTC-04:00
我他妈也是服了,每个人说的不一样,不过按照结果来说 java代码里应该是美国的UTC-5/6,注意本来是CST的 因为现在是夏天所以又是CDT。
此时有点晕了 理一理。
UTC=GMT 可以理解吧
GMT: 格林威治标准时间,英国伦敦格林威治定为 0° 经线开始的地方,地球每 15° 经度 被分为一个时区,共分为 24 个时区,相邻时区相差一小时。
UTC:世界协调时间,经严谨计算得到的时间,精确到秒,误差在 0.9s 以内, 是比 GMT 更为精确的世界时间。
东八区就是中国标准时间,它也是相对 GMT 而言的。所以,我们平时碰到相差 8 小时问题,就是因为中国标准时间和 GTM 相差 8 个时区,也就是相差 8 小时。
再来看 CST,百度百科里说 CST可视为中国、古巴的标准时间或美国、澳大利亚的中部时间,
这他m的一个CST代表四个不同的时区,怎么代表?
我们说的
美国本土横跨西五区至西八区,共四个时区,每个时区对应一个标准时间。从东向西分别为东部时间(EST)(西五区时间)、中部时间(CST)(西六区时间)、山地时间(MST)(西七区时间)、太平洋时间(西部时间)(PST)(西八区时间)。
又因为夏令时的存在CST!=GMT-6。
搞不动了。。