1、問(wèn)題描述
項(xiàng)目中通過(guò)時(shí)區(qū)名稱轉(zhuǎn)換為本地時(shí)間(JDK11.0.1),與數(shù)據(jù)庫(kù)(Postgresql12.3)轉(zhuǎn)換出來(lái)的本地時(shí)間相差一小時(shí)。當(dāng)時(shí)相差一小時(shí)就懷疑是夏令時(shí)的問(wèn)題造成的,但百度也沒(méi)有找到處理辦法,后面直接去jdk官網(wǎng)去看終于給找到原因。這是由于jdk時(shí)區(qū)庫(kù)沒(méi)有更新(lib/tzdb.dat),因?yàn)闀r(shí)區(qū)每年都會(huì)更新很多次,如果下載到本地的jdk的這個(gè)庫(kù)沒(méi)有更新,就有可能造成某些時(shí)區(qū)的時(shí)間轉(zhuǎn)換有問(wèn)題。
2、測(cè)試代碼
Postgresql根據(jù)時(shí)區(qū)獲取本地時(shí)間:
SELECT NOW() AT TIME ZONE 'America/Santiago';
Java根據(jù)時(shí)區(qū)名稱轉(zhuǎn)換本地時(shí)間(在JDK的時(shí)區(qū)庫(kù)沒(méi)有更新的情況下JDK11.0.1與JDK11.0.11執(zhí)行的結(jié)果都還不一樣,其它版本的也會(huì)存在該問(wèn)題):
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
public class TimeZoneTest{
public static void main(String[] args){
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String zoneName = "America/Santiago";
ZoneId zoneId;
try{
zoneId = ZoneId.of(zoneName);
}catch(Exception e){
zoneId = ZoneId.of(ZoneId.SHORT_IDS.get(zoneName));
}
ZoneOffset offset = zoneId.getRules().getOffset(Instant.now());
String time = OffsetDateTime.now().toInstant().atOffset(offset).format(fmt);
System.out.println(String.format("\n\ntzName : %s, offset : %s, time : %s\n\n",offset,offset.getTotalSeconds(),time));
}
}
3、查看JDK本地時(shí)區(qū)庫(kù)版本
下載官方的tzupdater工具,完成后執(zhí)行以下命令查看(tzupdater說(shuō)明文檔):
java -jar tzupdater.jar -V
4、更新JDK本地時(shí)區(qū)庫(kù)
java -jar tzupdater.jar -l
完成后再執(zhí)行第2點(diǎn)中的測(cè)試代碼,這時(shí)轉(zhuǎn)換的本地時(shí)間就正常了。
5、其它相關(guān)資源
JDK不同版本對(duì)應(yīng)的時(shí)區(qū)庫(kù)版本地址:https://www.oracle.com/java/technologies/tzdata-versions.html
JDK時(shí)區(qū)相關(guān)的文檔地址:https://www.oracle.com/java/technologies/javase/timezones.html
時(shí)區(qū)庫(kù)地址:https://www.iana.org/time-zones