转载

docker java 时区

之前的文章提到过把镜像的/etc/localtime 删除后挂载本地的就可以解决问题,但是最近更新了centos7的基础镜像,发现时间又少了8个小时,确认了下镜像制作没问题,但是依然出现了,百思不得其解,于是把java获取时区的代码抠出来了

#include<stdlib.h>
#include<stdio.h>
#include<strings.h>
#include<time.h>
#include<limits.h>
#include<errno.h>
#include<stddef.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<string.h>
#include<dirent.h>
#include<unistd.h>
#include<fcntl.h>

static const char *ETC_TIMEZONE_FILE = "/etc/timezone";
static const char *ZONEINFO_DIR = "/usr/share/zoneinfo";
static const char *DEFAULT_ZONEINFO_FILE = "/etc/localtime";

static char *
getZoneName(char *str)
{
    static const char *zidir = "zoneinfo/";

    char *pos = strstr((const char *)str, zidir);
    if (pos == NULL) {
        return NULL;
    }
    return pos + strlen(zidir);
}

/*
 * Returns a path name created from the given 'dir' and 'name' under
 * UNIX. This function allocates memory for the pathname calling
 * malloc(). NULL is returned if malloc() fails.
 */
static char *
getPathName(const char *dir, const char *name) {
    char *path;

    path = (char *) malloc(strlen(dir) + strlen(name) + 2);
    if (path == NULL) {
        return NULL;
    }
    return strcat(strcat(strcpy(path, dir), "/"), name);
}


static char *
findZoneinfoFile(char *buf, size_t size, const char *dir)
{
    DIR *dirp = NULL;
    struct stat statbuf;
    struct dirent *dp = NULL;
    struct dirent *entry = NULL;
    char *pathname = NULL;
    int fd = -1;
    char *dbuf = NULL;
    char *tz = NULL;

    dirp = opendir(dir);
    if (dirp == NULL) {
        return NULL;
    }

    entry = (struct dirent *) malloc((size_t) pathconf(dir, _PC_NAME_MAX));
    if (entry == NULL) {
        (void) closedir(dirp);
        return NULL;
    }

#ifdefined(__linux__) || defined(MACOSX) || (defined(__solaris__) /
    && (defined(_POSIX_PTHREAD_SEMANTICS) || defined(_LP64)))
    while (readdir_r(dirp, entry, &dp) == 0 && dp != NULL) {
#else
    while ((dp = readdir_r(dirp, entry)) != NULL) {
#endif

        /*
         * Skip '.' and '..' (and possibly other .* files)
         */
        if (dp->d_name[0] == '.') {
            continue;
        }

        /*
         * Skip "ROC", "posixrules", and "localtime".
         */
        if ((strcmp(dp->d_name, "ROC") == 0)
            || (strcmp(dp->d_name, "posixrules") == 0)
#ifdef __solaris__
            /*
             * Skip the "src" and "tab" directories on Solaris.
             */
            || (strcmp(dp->d_name, "src") == 0)
            || (strcmp(dp->d_name, "tab") == 0)
#endif
            || (strcmp(dp->d_name, "localtime") == 0)) {
            continue;
        }

        pathname = getPathName(dir, dp->d_name);
        if (pathname == NULL) {
            break;
        }
        if (stat(pathname, &statbuf) == -1) {
            break;
        }

        if (S_ISDIR(statbuf.st_mode)) {
            tz = findZoneinfoFile(buf, size, pathname);
            if (tz != NULL) {
                break;
            }
        // 这里失败 usr share zoneinfo asia 目录下 所有的文件都通不S_ISREG 这个函数
        } else if (S_ISREG(statbuf.st_mode) && (size_t)statbuf.st_size == size) {
            dbuf = (char *) malloc(size);
            if (dbuf == NULL) {
                break;
            }
            if ((fd = open(pathname, O_RDONLY)) == -1) {
                break;
            }
            if (read(fd, dbuf, size) != (ssize_t) size) {
                break;
            }
            if (memcmp(buf, dbuf, size) == 0) {
                tz = getZoneName(pathname);
                if (tz != NULL) {
                    tz = strdup(tz);
                }
                break;
            }
            free((void *) dbuf);
            dbuf = NULL;
            (void) close(fd);
            fd = -1;
        }
        free((void *) pathname);
        pathname = NULL;
    }

    if (entry != NULL) {
        free((void *) entry);
    }
    if (dirp != NULL) {
        (void) closedir(dirp);
    }
    if (pathname != NULL) {
        free((void *) pathname);
    }
    if (fd != -1) {
        (void) close(fd);
    }
    if (dbuf != NULL) {
        free((void *) dbuf);
    }
    return tz;
}



int main(){
struct stat statbuf;	    
    char *tz = NULL;
    FILE *fp;
    int fd;
    char *buf;
    size_t size;
    if ((fd = open(DEFAULT_ZONEINFO_FILE, O_RDONLY)) == -1) {
        return NULL;
    }
    if (fstat(fd, &statbuf) == -1) {
        (void) close(fd);
        return NULL;
    }
    size = (size_t) statbuf.st_size;
    buf = (char *) malloc(size);
    if (buf == NULL) {
        (void) close(fd);
        return NULL;
    }

    if (read(fd, buf, size) != (ssize_t) size) {
        (void) close(fd);
        free((void *) buf);
        return NULL;
    }
    (void) close(fd);

    tz = findZoneinfoFile(buf, size, ZONEINFO_DIR);
    printf("%s", tz);
    free((void *) buf);

return 0;

}

总结

docker 仓库上centos:7的基础镜像一直在更新,虽然是都叫centos:7但是一直都在默默的更新着,处于可控性考虑,还是得自己从头做一个基础镜像,为了彻底解决java时区问题,删除镜像localtime的同时,挂载localtime和/user/share/zoneinfo

原文  https://chellynov.github.io/2018/12/30/java-timezon/
正文到此结束
Loading...