• Java读取系统默认时区


    工作中,遇到一个Java读取默认时区的问题,后来看了openjdk的源码,大致整理一下过程

    public class Test {
        public void test(){
            TimeZone.getDefault();
        }
    }

    TimeZone.getDefault()会跳到下面代码:

        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方法

    zoneID = getSystemTimeZoneID(javaHome);

    这个方法的实现,可以参考

    openjdk-8u40-src-b25-10_feb_2015openjdkjdksrcshare
    ativejavautilTimeZone.c
    JNIEXPORT jstring JNICALL
    Java_java_util_TimeZone_getSystemTimeZoneID(JNIEnv *env, jclass ign,
                                                jstring java_home)
    {
        const char *java_home_dir;
        char *javaTZ;
        jstring jstrJavaTZ = NULL;
    
        CHECK_NULL_RETURN(java_home, NULL);
    
        java_home_dir = JNU_GetStringPlatformChars(env, java_home, 0);
        CHECK_NULL_RETURN(java_home_dir, NULL);
    
        /*
         * Invoke platform dependent mapping function
         */
        javaTZ = findJavaTZ_md(java_home_dir);
        if (javaTZ != NULL) {
            jstrJavaTZ = JNU_NewStringPlatform(env, javaTZ);
            free((void *)javaTZ);
        }
    
        JNU_ReleaseStringPlatformChars(env, java_home, java_home_dir);
        return jstrJavaTZ;
    }

    主要看:

    javaTZ = findJavaTZ_md(java_home_dir);

    继续参考,下面TimeZone_md.c文件,可以知道find_JavaTZ_md方法的实现

    openjdk-8u40-src-b25-10_feb_2015openjdkjdksrcsolaris
    ativejavautilTimeZone_md.c
    char *
    findJavaTZ_md(const char *java_home_dir)
    {
        char *tz;
        char *javatz = NULL;
        char *freetz = NULL;
    
        tz = getenv("TZ");
    
    #if defined(__linux__) || defined(_ALLBSD_SOURCE)
        if (tz == NULL) {
    #else
    #if defined (__solaris__) || defined(_AIX)
        if (tz == NULL || *tz == '') {
    #endif
    #endif
            tz = getPlatformTimeZoneID();
            freetz = tz;
        }
    
        /*
         * Remove any preceding ':'
         */
        if (tz != NULL && *tz == ':') {
            tz++;
        }
    
    #ifdef __solaris__
        if (tz != NULL && strcmp(tz, "localtime") == 0) {
            tz = getSolarisDefaultZoneID();
            freetz = tz;
        }
    #endif
    
        if (tz != NULL) {
    #ifdef __linux__
            /*
             * Ignore "posix/" prefix.
             */
            if (strncmp(tz, "posix/", 6) == 0) {
                tz += 6;
            }
    #endif
            javatz = strdup(tz);
            if (freetz != NULL) {
                free((void *) freetz);
            }
    
    #ifdef _AIX
            freetz = mapPlatformToJavaTimezone(java_home_dir, javatz);
            if (javatz != NULL) {
                free((void *) javatz);
            }
            javatz = freetz;
    #endif
        }
    
        return javatz;
    }

    tz = getPlatformTimeZoneID(),这个函数内容,就不贴了,可以自己看下,总计起来,在Linux系统上,大概过程为以下几步:

    1.先找“TZ”变量,没有,到2,

    2.读/etc/timezone,没有到3,

    3.比较/etc/localtime文件与"/usr/share/zoneinfo目录下所有时区文件,如果有一致的,就为该时区,如果没有,到4,

    4.默认为标准GMT

    如有不正确的地方,欢迎指正!

    
    
    
    
  • 相关阅读:
    赏月斋源码共享计划 第三期
    概率校准与Brier分数
    模型评估——定量分析预测的质量
    Sklearn实现逻辑回归
    赏月斋源码共享计划 第二期
    技术路线范文
    开题报告范文
    赏月斋源码共享计划 第一期
    关于研究课题中的技术路线与实施方案
    Git项目的初始化
  • 原文地址:https://www.cnblogs.com/darange/p/9368245.html
Copyright © 2020-2023  润新知