关于时区转换的struct tm和mktime()的接口契约

时间:2018-02-01 19:17:48

标签: c mktime

在运行以下C代码时,我注意到mktime()在调用时显然会进行一些时区转换。

void process_time(struct tm * pt) {
    printf("pt %02d-%02d-%02d %02d:%02d:%02d\n", pt->tm_year, pt->tm_mon, pt->tm_mday,
            pt->tm_hour, pt->tm_min, pt->tm_sec);

    ret = mktime(pt);

    printf("pt %02d-%02d-%02d %02d:%02d:%02d\n", pt->tm_year, pt->tm_mon, pt->tm_mday,
            pt->tm_hour, pt->tm_min, pt->tm_sec);

    /* more code here */
}

在某些情况下(原因是某些struct tm成员未正确初始化),我注意到在调用mktime()后,pt->tm_hour比一个struct tm少一个以前。本地系统时间是UTC以东一小时,因此对应于本地到UTC的转换。

根据this source/usr/include/time.h除了工作日,一年中的某一天和DST标志外,应该只有通常的YYYY-MM-DD-hh-mm-ss字段 - 没有提及时区或UTC偏移量。

但是,当我在Ubuntu(struct tm)上检查结构时,我注意到两个额外的UTC偏移字段和一个时区字符串。

struct tm的接口合约是什么?它是否要求这些时区转换,如果是,那么在mktime()对其进行规范化后,tail -f "scheduler_$(date '+%m%d%y').log" | perl -pe 's/^/$_=qx(date +%T_); chomp; $_/e' 成员应该如何解释时区?

2 个答案:

答案 0 :(得分:2)

struct tm的接口合约是什么?

mktime()规范的关键部分是:

  

mktime函数转换细分时间,表示为本地时间 ...将忽略结构的tm_wdaytm_yday组件的原始值,并且其他组件的原始值不限于上述范围。 ......成功了   完成,...组件设置为表示指定的日历   时间,但他们的价值被强制到上述范围   C11dr§7.27.2.32

忽略tm_wdaytm_yday的值。成员指定年,月,日,小时,分钟,秒 .isdst贡献,但其他平台指定的会影响结果。这可能包括纳秒,时区,UTC偏移等成员。

强大的代码设置所有成员。

struct tm t = {0};        // clear **all** members
t.tm_year = 2018 - 1900;  // Assign some members
t.tm_mon = 2 - 1;
t.tm_mday = 1; // today
t.tm_isdst = -1;          // Let system determine if DST applies for this date
process_time(&t);
  

我注意到在调用mktime()之后,pt-> tm_hour比之前少了一个。

这可能是由于.tm_isdst < 0造成的。

  

如果夏令时生效,则tm_isdst的值为正,如果夏令时不生效,则为零,如果信息不可用,则为负。 §7.27.14
  脚注320:负值使其尝试确定夏令时是否在指定时间内有效。

.tm_isdst添加到process_time()中的2行以查看效果。

 printf("pt %02d-%02d-%02d %02d:%02d:%02d  %d\n", 
     pt->tm_year, pt->tm_mon, pt->tm_mday, 
     pt->tm_hour, pt->tm_min, pt->tm_sec, pt->tm_isdst);
  

struct tm对其进行规范化后,mktime()成员应该如何解释时区?

作为规范化的当地时间。

答案 1 :(得分:1)

chux回答了大部分问题。这里有更多信息。

您询问了tm_gmtofftm_zone。这些是struct tm的非标准添加,虽然它们非常有用且非常常见。它们在mktime的输入时被忽略,但在输出上设置。它们可能与你看到的不寻常的结果无关。