代码之家  ›  专栏  ›  技术社区  ›  Cheiron

localtime,mktime:第二次规范化和DST行为

  •  1
  • Cheiron  · 技术社区  · 6 年前

    以下面的代码为例:

    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;
    }
    

    函数的作用是:修改tm结构的字段 如下所示:tm_wday和tm_yday设置为根据 字段;如果结构成员超出其有效间隔,则将对其进行规范化(例如,10月40日为 改为11月9日); tmu 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)
    

    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)
    

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

    所以,我的问题是:真的有错误吗?或者这是记录在案的行为,在什么地方?

    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 回复  |  直到 6 年前
        1
  •  0
  •   Sander De Dycker    6 年前

    根据您的确切时区(和管辖区),在2018年10月28日清晨的某个时间,时钟向后移动1小时,因为 DST 末端。从你的例子来看,这似乎发生在你所在时区/辖区的3点。

    tm_sec 值超出正常范围(0-59),因此 mktime

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

    在第二种情况下(2018-10-28,1:52:16,增加2小时) tm_hour mktime公司 无法确定您已经添加了2个小时,它只是将其视为本地时间。结果是2018-10-28,3:52:16,也就是2018-10-28,1:52:16之后的3小时。

    • 不重置 tm\U isdst公司 -1 除非需要(而且你知道会发生什么)
    • 尽可能使用UTC时间戳,并且在显示时仅转换为本地时间。