当地时间,mktime:二次标准化和DST行为

时间:2018-09-03 10:16:33

标签: c time localtime mktime

采用以下代码:

static void printTime(const struct tm* t, const time_t stamp){
    printf("%d-%d-%d, %d:%d:%d (DST %s) (stamp: %zu)\n",
            1900 + t->tm_year, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, t->tm_isdst ? "Active" : "Inactive", stamp);
}

int main(){
    time_t t = 1540633936;
    struct tm tStruct;
    localtime_r(&t, &tStruct);
    printTime(&tStruct, t);
    for (unsigned i = 0; i < 14; ++i){
        tStruct.tm_sec += 7200;
        //tStruct.tm_hour += 2;
        tStruct.tm_isdst = -1;
        t = mktime(&tStruct);
        localtime_r(&t, &tStruct);
        printTime(&tStruct, t);
    }
    return 0;
}

它显示了两种增加日期的方法。 mktime的文档告诉我:

  

mktime()函数将tm结构的字段修改为   如下:tm_wday和tm_yday设置为从   其他的内容          领域如果结构成员超出其有效间隔,则会对其进行规范化(例如,10月40日为   改为11月9日);          将tm_isdst设置为(无论其初始值如何)为正值或设置为0,以指示DST是否在   在指定的效果          时间。

基于此,我希望规范化的工作方式是,增加7200秒等同于增加两个小时。但是输出有所不同:

tStruct.tm_sec += 7200;

礼物:

2018-10-27, 11:52:16 (DST Active) (stamp: 1540633936)
2018-10-27, 13:52:16 (DST Active) (stamp: 1540641136)
2018-10-27, 15:52:16 (DST Active) (stamp: 1540648336)
2018-10-27, 17:52:16 (DST Active) (stamp: 1540655536)
2018-10-27, 19:52:16 (DST Active) (stamp: 1540662736)
2018-10-27, 21:52:16 (DST Active) (stamp: 1540669936)
2018-10-27, 23:52:16 (DST Active) (stamp: 1540677136)
2018-10-28, 1:52:16 (DST Active) (stamp: 1540684336)
2018-10-28, 2:52:16 (DST Inactive) (stamp: 1540691536)
2018-10-28, 3:52:16 (DST Inactive) (stamp: 1540695136)
2018-10-28, 5:52:16 (DST Inactive) (stamp: 1540702336)
2018-10-28, 7:52:16 (DST Inactive) (stamp: 1540709536)
2018-10-28, 9:52:16 (DST Inactive) (stamp: 1540716736)
2018-10-28, 11:52:16 (DST Inactive) (stamp: 1540723936)
2018-10-28, 13:52:16 (DST Inactive) (stamp: 1540731136)

(请注意DST更改后立即出现错误的时间跳动)

tStruct.tm_hour += 2;

礼物:

2018-10-27, 11:52:16 (DST Active) (stamp: 1540633936)
2018-10-27, 13:52:16 (DST Active) (stamp: 1540641136)
2018-10-27, 15:52:16 (DST Active) (stamp: 1540648336)
2018-10-27, 17:52:16 (DST Active) (stamp: 1540655536)
2018-10-27, 19:52:16 (DST Active) (stamp: 1540662736)
2018-10-27, 21:52:16 (DST Active) (stamp: 1540669936)
2018-10-27, 23:52:16 (DST Active) (stamp: 1540677136)
2018-10-28, 1:52:16 (DST Active) (stamp: 1540684336)
2018-10-28, 3:52:16 (DST Inactive) (stamp: 1540695136)
2018-10-28, 5:52:16 (DST Inactive) (stamp: 1540702336)
2018-10-28, 7:52:16 (DST Inactive) (stamp: 1540709536)
2018-10-28, 9:52:16 (DST Inactive) (stamp: 1540716736)
2018-10-28, 11:52:16 (DST Inactive) (stamp: 1540723936)
2018-10-28, 13:52:16 (DST Inactive) (stamp: 1540731136)
2018-10-28, 15:52:16 (DST Inactive) (stamp: 1540738336)

(至少对我来说)这是预期的行为。

所以,我的问题是:实际上有错误吗?还是在某些地方记录了这种行为?

当mktime需要更改tm_hour时,也会发生此行为。请看以下示例:

tStruct.tm_hour += 25;

礼物:

2018-10-27, 11:52:16 (DST Active) (stamp: 1540633936)
2018-10-28, 12:52:16 (DST Inactive) (stamp: 1540727536)
2018-10-29, 13:52:16 (DST Inactive) (stamp: 1540817536)
2018-10-30, 14:52:16 (DST Inactive) (stamp: 1540907536)
2018-10-31, 15:52:16 (DST Inactive) (stamp: 1540997536)
2018-11-1, 16:52:16 (DST Inactive) (stamp: 1541087536)
2018-11-2, 17:52:16 (DST Inactive) (stamp: 1541177536)
2018-11-3, 18:52:16 (DST Inactive) (stamp: 1541267536)
2018-11-4, 19:52:16 (DST Inactive) (stamp: 1541357536)
2018-11-5, 20:52:16 (DST Inactive) (stamp: 1541447536)
2018-11-6, 21:52:16 (DST Inactive) (stamp: 1541537536)
2018-11-7, 22:52:16 (DST Inactive) (stamp: 1541627536)
2018-11-8, 23:52:16 (DST Inactive) (stamp: 1541717536)
2018-11-10, 0:52:16 (DST Inactive) (stamp: 1541807536)
2018-11-11, 1:52:16 (DST Inactive) (stamp: 1541897536)
tStruct.tm_sec += 90000

礼物:

2018-10-27, 11:52:16 (DST Active) (stamp: 1540633936)
2018-10-28, 11:52:16 (DST Inactive) (stamp: 1540723936)
2018-10-29, 12:52:16 (DST Inactive) (stamp: 1540813936)
2018-10-30, 13:52:16 (DST Inactive) (stamp: 1540903936)
2018-10-31, 14:52:16 (DST Inactive) (stamp: 1540993936)
2018-11-1, 15:52:16 (DST Inactive) (stamp: 1541083936)
2018-11-2, 16:52:16 (DST Inactive) (stamp: 1541173936)
2018-11-3, 17:52:16 (DST Inactive) (stamp: 1541263936)
2018-11-4, 18:52:16 (DST Inactive) (stamp: 1541353936)
2018-11-5, 19:52:16 (DST Inactive) (stamp: 1541443936)
2018-11-6, 20:52:16 (DST Inactive) (stamp: 1541533936)
2018-11-7, 21:52:16 (DST Inactive) (stamp: 1541623936)
2018-11-8, 22:52:16 (DST Inactive) (stamp: 1541713936)
2018-11-9, 23:52:16 (DST Inactive) (stamp: 1541803936)
2018-11-11, 0:52:16 (DST Inactive) (stamp: 1541893936)

1 个答案:

答案 0 :(得分:0)

根据您的确切时区(和管辖区),由于DST结束,时钟会在清晨的某个时间2018-10-28移回1小时。从您的示例来看,这似乎发生在您所在时区/辖区的3:00。

在第一种情况下(到2018-10-28,1:52:16加7200秒),tm_sec值超出正常范围(0-59),因此mktime可以确定您已经增加了2个小时,并且由于它知道这是穿越DST边界的,因此可以相应地调整时间。结果为2018-10-28,2:52:16,这是2018-10-28,1:52:16之后的2小时。

对于第一种情况下的下一个增量(到2018-10-28,2:52:16增加了7200秒),再次发生了完全相同的事情(因为您再次遍历了DST边界-您已重置{毕竟是{1}}到tm_isdst。结果为2018-10-28,3:52:16,这是2018-10-28,2:52:16之后的2小时。

在第二种情况下(到2018-10-28,1:52:16增加2个小时),-1值仍在正常范围(0-23)之内,因此{{1} }不能确定您已经添加了2个小时,而只是将其视为本地时间。结果为2018-10-28,3:52:16,也就是2018-10-28,1:52:16 3小时之后。

为避免此类问题:

  • 除非有必要,否则请勿将tm_hour重置为mktime(您将了解会发生的事情)
  • 尽可能使用UTC时间戳,并且仅在显示时转换为本地时间。