使用WinAPI进行夏令时和UTC到本地时间的转换

ahm*_*md0 4 c c++ windows winapi dst

我正在尝试查看WindAPI是否从本地转换为UTC时间,反之亦然是夏令时准确.例如,让我们使用LocalFileTimeToFileTime API.它的描述说明:

LocalFileTimeToFileTime使用时区和夏令时的当前设置.因此,如果是夏令时,此功能将考虑夏令时,即使您要转换的时间是标准时间.

所以我用这段代码测试它:

//Say, if DST change takes place on Mar-8-2015 at 2:00:00 AM
//when the clock is set 1 hr forward

//Let's check the difference between two times:
SYSTEMTIME st1_local = {2015, 3, 0, 8, 1, 30, 0, 0};    //Mar-8-2015 1:30:00 AM
SYSTEMTIME st2_local = {2015, 3, 0, 8, 3, 30, 0, 0};    //Mar-8-2015 3:30:00 AM

//Convert to file-time format
FILETIME ft1_local, ft2_local;
VERIFY(::SystemTimeToFileTime(&st1_local, &ft1_local));
VERIFY(::SystemTimeToFileTime(&st2_local, &ft2_local));

//Then convert from local to UTC time
FILETIME ft1_utc, ft2_utc;
VERIFY(::LocalFileTimeToFileTime(&ft1_local, &ft1_utc));
VERIFY(::LocalFileTimeToFileTime(&ft2_local, &ft2_utc));

//Get the difference
LONGLONG iiDiff100ns = (((LONGLONG)ft2_utc.dwHighDateTime << 32) | ft2_utc.dwLowDateTime) -
    (((LONGLONG)ft1_utc.dwHighDateTime << 32) | ft1_utc.dwLowDateTime);

//Convert from 100ns to seconds
LONGLONG iiDiffSecs = iiDiff100ns / 10000000LL;

//I would expect 1 hr
ASSERT(iiDiffSecs == 3600); //But I get 7200, which is 2 hrs!
Run Code Online (Sandbox Code Playgroud)

那我在这里错过了什么?

Cro*_*man 6

SystemTimeToFileTime()将其第一个参数解释为UTC时间(没有DST概念),因此您ft1_localft2_local对象将始终相隔两个小时,因为您正在更改数据格式,而不是实际的时间点.LocalFileTimeToFileTime()然后将相同的偏移应用于你传递给它的任何东西,所以ft1_utc并且ft2_utc总是会相隔两个小时.

正如文档所说," LocalFileTimeToFileTime 使用时区和夏令时的当前设置 "(强调我的),所以如果在当前时间比你落后UTC四小时,它只会从任何时候扣除4小时你传递给它的时间,无论这段时间最初代表DST的另一边.

编辑:根据评论,这里是你如何获得标准C中两个本地时间之间的秒差:

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

int main(void) {
    struct tm start_time;
    start_time.tm_year = 115;
    start_time.tm_mon = 2;
    start_time.tm_mday = 8;
    start_time.tm_hour = 1;
    start_time.tm_min = 30;
    start_time.tm_sec = 0;
    start_time.tm_isdst = -1;

    struct tm end_time;
    end_time.tm_year = 115;
    end_time.tm_mon = 2;
    end_time.tm_mday = 8;
    end_time.tm_hour = 3;
    end_time.tm_min = 30;
    end_time.tm_sec = 0;
    end_time.tm_isdst = -1;

    time_t start_tm = mktime(&start_time);
    time_t end_tm = mktime(&end_time);

    if ( start_tm == -1 || end_tm == -1 ) {
        fputs("Couldn't get local time.", stderr);
        exit(EXIT_FAILURE);
    }

    double seconds_diff = difftime(end_tm, start_tm);
    printf("There are %.1f seconds difference.\n", seconds_diff);

    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

哪个输出:

paul@thoth:~/src$ ./difftime
There are 3600.0 seconds difference.
paul@thoth:~/src$ 
Run Code Online (Sandbox Code Playgroud)

正如你所期待的那样.

请注意,使用struct tm:

  • tm_year 以1900年以来的年份表示,所以到2015年我们写了115

  • tm_mon 在0到11的范围内,所以3月是2,而不是3.

  • 其他时间成员就像你期望的那样

  • tm_isdst设置为时-1,mktime()将尝试自行查找DST是否在我们提供的当地时间生效,这是我们希望它在这里做的.