将UTC日期和时间转换为UNIX时间会给出错误的值(时区不同)。为什么?

时间:2019-01-22 10:17:47

标签: c utc epoch

我写了一个小函数将UTC中的日期和时间转换为UNIX时间(Epoch时间)。但是,我获得的值取决于我所在的时区。

这是代码

#include<stdio.h>
#include<time.h>

time_t GenerateUnixTimeStampFromDateAndTime(char *DateAndTime);

void main()
{
    long int UnixTime=0;
    char *CurrentTime="01/22/2019 06:30:00";

    UnixTime = (long int)GenerateUnixTimeStampFromDateAndTime(CurrentTime);
    printf("Current Unix Time= %ld\r\n", UnixTime);
}

time_t GenerateUnixTimeStampFromDateAndTime(char *DateAndTime) 
{
    struct tm ti={0};
    if( sscanf(DateAndTime, "%d/%d/%d %d:%d:%d", &ti.tm_mon, &ti.tm_mday, &ti.tm_year, &ti.tm_hour, &ti.tm_min, &ti.tm_sec) != 6 )
        return -1;
    ti.tm_year = ti.tm_year - 1900;
    ti.tm_mon = ti.tm_mon - 1;

    return mktime(&ti);
}

我得到的答案是1548118800,它是01/22/2019 01:00:00即-5:30,这是我所在的时区(印度)。如果我将PC时区更改为UTC,则它会给出正确的值1548138600。

要使其与时区无关,我需要进行哪些更改?

1 个答案:

答案 0 :(得分:1)

如记录所示,mktime()采用本地时间中细分的时间部分。

首先,保存用户当前时区:

char  *old_timezone, *temp;

temp = getenv("TZ");
if (temp) {
    const size_t  len = temp;
    old_timezone = malloc(len + 1);
    if (!old_timezone) {
        fprintf(stderr, "Out of memory!\n");
        exit(EXIT_FAILURE);
    }
    if (len > 0)
        memcpy(old_timezone, temp, len);
    old_timezone[len] = '\0';
} else
    old_timezone = NULL;

如果用户使用系统默认值,则old_timezone将为NULL。

接下来,将当前时区(针对该过程)设置为UTC:

setenv("TZ", "UTC", 1);
tzset();

请注意,如果需要,可以使用任何时区说明符,而不是上面的"UTC";有关详细信息,请参见tzset()tzset()调用通常是由您的C库在内部完成的,但是在此处明确地执行此操作有助于我们人类看到时区特定的情况。

这时,mktime()将以UTC运行,而localtime()gmtime()将返回相同的结果。

然后,将时区还原为

if (old_timezone) {
    setenv("TZ", old_timezone, 1);
    free(old_timezone);
    old_timezone = NULL;
} else
    unsetenv("TZ");
tzset();

请注意,这不会影响当前进程(以及您可能通过popen()system()fork()exec()创建的任何子进程)。时区与语言环境一样,是每个进程的属性。


运行

    unsetenv("TZ");
    tzset();

会将此过程的当前时区更改为系统默认时区。


如果您的程序在UTC中明确运行,则只需

    /* This program works explicitly in the UTC timezone.
       User/system timezone configuration is completely ignored. */
    setenv("TZ", "UTC", 1");
    tzset();

main()开头附近。