zoukankan      html  css  js  c++  java
  • Java程序读取时间比MySql时间早了8个小时

      昨天碰见一个问题,需要从数据库中读取数据传输给其他平台,从其他平台查看数据的时候发现时间不正确,多了8个小时,查看接收日志,接收到的时间是不正确,说明发送的时候应该就是不正确的,从发送程序查,发现发送的时候就是不正确的,而数据库的时间是正确的,上网查了下,发现是连接数据库的时候设置的时区不正确,连接数据库时设置的是serverTimezone=UTC,UTC是标准时间,比中国时间(东八区)时间早了8个小时,所以导致的不正确。网上的结论到这里就结束了,感觉还少了一部分,又上网查了下java程序运行的时候也有自己的时区,如果不设置的话一般会从系统中取,如果设置数据库的时区和系统时区一致,那没有问题,如果时间不一致的话,就会出现问题。

    获取当前程序所用时区:

        public static void main(String[] args) {
            Calendar ca = Calendar.getInstance();
            TimeZone tz = ca.getTimeZone();
            System.out.println(tz.getID());
        }
    

    控制台输出:Asia/Shanghai,而连接数据库的时候设置的时区是serverTimezone=UTC
    这时候就会出现问题,完整的流程应该是,程序从数据库获取时间,获取时间的时候会看根据连接数据库的时候设置的时区进行转化,比如数据库时间是2021-11-30 00:00:00,但是程序从数据库取到后会比较两者的时区,时区不一致时会进行转化,UTC要比东八区慢八个小时,所以取到时间后会增加8个小时,获取的时间是2021-11-30 08:00:00,到这里算是一个完成流程。
    既然存入的时候会根据时区修改时间,那存入的时候也会做对应的修改,程序设置的时区是Asia/Shanghai,连接MySql时设置的时区是UTC,如果程序接收到时间是2021-11-30 00:00:00,那存入到数据库中的时间为2021-10-31 16:00:00,数据库的时间比程序设定时间慢8个小时,所以会再减少8个小时。
    将连接数据库的serverTimezone设置为serverTimezone=Asia/Shanghai或者serverTimezone=GMT%2B8即可解决问题。

    到这里问题已经解决,后来看了下源码,程序会获取系统时间,如果获取不到的话会用默认时间GMT,也是0时区。

    下面是部分源码:

     private static synchronized TimeZone setDefaultZone() {
            TimeZone tz;
            // get the time zone ID from the system properties
            String zoneID = AccessController.doPrivileged(
                    new GetPropertyAction("user.timezone"));
    
            // if the time zone ID is not set (yet), perform the
            // platform to Java time zone ID mapping.
            if (zoneID == null || zoneID.isEmpty()) {
                String javaHome = AccessController.doPrivileged(
                        new GetPropertyAction("java.home"));
                try {
                    zoneID = getSystemTimeZoneID(javaHome);
                    if (zoneID == null) {
                        zoneID = GMT_ID;
                    }
                } catch (NullPointerException e) {
                    zoneID = GMT_ID;
                }
            }
    
            // Get the time zone for zoneID. But not fall back to
            // "GMT" here.
            tz = getTimeZone(zoneID, false);
    
            if (tz == null) {
                // If the given zone ID is unknown in Java, try to
                // get the GMT-offset-based time zone ID,
                // a.k.a. custom time zone ID (e.g., "GMT-08:00").
                String gmtOffsetID = getSystemGMTOffsetID();
                if (gmtOffsetID != null) {
                    zoneID = gmtOffsetID;
                }
                tz = getTimeZone(zoneID, true);
            }
            assert tz != null;
    
            final String id = zoneID;
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                @Override
                    public Void run() {
                        System.setProperty("user.timezone", id);
                        return null;
                    }
                });
    
            defaultTimeZone = tz;
            return tz;
        }
    

    源码看到这里的时候,已经有native方法了,搜了下,没想到网上有大佬把调用的方法也写出来了,Java读取系统默认时区 ,这位老哥写的确实挺全的,想看的同学可以看下。

    金无足赤,人无完人,若有文章什么问题欢迎各位批评指正,共同交流,共同进步。 另,人过留名,雁过留声,少侠觉得还行的话留下个赞吧!:)
  • 相关阅读:
    windows下载
    vue-element-admin改造步骤
    js处理url
    好用的工具
    数据库设计工具
    虚拟机使用
    Mac上编译C
    MAC系统配置
    SQL语法
    SSMP一次请求数据处理过程分析
  • 原文地址:https://www.cnblogs.com/thePeaceOftheLord/p/15625293.html
Copyright © 2011-2022 走看看