1、问题描述
项目中通过时区名称转换为本地时间(JDK11.0.1),与数据库(Postgresql12.3)转换出来的本地时间相差一小时。当时相差一小时就怀疑是夏令时的问题造成的,但百度也没有找到处理办法,后面直接去jdk官网去看终于给找到原因。这是由于jdk时区库没有更新(lib/tzdb.dat),因为时区每年都会更新很多次,如果下载到本地的jdk的这个库没有更新,就有可能造成某些时区的时间转换有问题。
2、测试代码
Postgresql根据时区获取本地时间:
SELECT NOW() AT TIME ZONE 'America/Santiago';
Java根据时区名称转换本地时间(在JDK的时区库没有更新的情况下JDK11.0.1与JDK11.0.11执行的结果都还不一样,其它版本的也会存在该问题):
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本地时区库版本
下载官方的tzupdater工具,完成后执行以下命令查看(tzupdater说明文档):
java -jar tzupdater.jar -V
4、更新JDK本地时区库
java -jar tzupdater.jar -l
完成后再执行第2点中的测试代码,这时转换的本地时间就正常了。
5、其它相关资源
JDK不同版本对应的时区库版本地址:https://www.oracle.com/java/technologies/tzdata-versions.html
JDK时区相关的文档地址:https://www.oracle.com/java/technologies/javase/timezones.html