mktime和tm_isdst

时间:2011-12-19 08:50:54

标签: c unix time freebsd mktime

我在这里想到了很多不同的观点。

我看了man mktime

 (A positive or zero value for tm_isdst causes mktime() to presume initially
 that summer time (for example, Daylight Saving Time) is or is not in
 effect for the specified time, respectively.  A negative value for
 tm_isdst causes the mktime() function to attempt to divine whether summer
 time is in effect for the specified time. 

我的问题是,tm_isdst不应该-1保留为{{1}}让系统决定它是否为dst,以及代码是否与dst无关?

我错过了什么吗?

3 个答案:

答案 0 :(得分:10)

如果可能,您应该避免将tm_isdst设置为-1。系统无法始终仅从日期和时间确定DST状态。在夏令时结束之前和之后的一小时,这是模棱两可的。例如,如果您在2012年11月4日凌晨1:30之前通过了mktime(),则该信息不足以从time_t获取正确的mktime()值。通常我看到mktime()假设标准时间不明确,但我没有看到任何文档保证所有平台上的行为。 2012年11月4日凌晨1:30,tm_isdst == 1将是1小时前,因为小时1:00:00至1:59:59重复。

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

int main()
{
    time_t daylight, standard;
    struct tm timestr;
    double diff;

    timestr.tm_year = 2012 - 1900;
    timestr.tm_mon = 11 - 1;
    timestr.tm_mday = 4;
    timestr.tm_hour = 1;
    timestr.tm_min = 30;
    timestr.tm_sec = 0;

    /* first with standard time */
    timestr.tm_isdst = 0;
    standard = mktime(&timestr);

    /* now with daylight time */
    timestr.tm_isdst = 1;
    daylight = mktime(&timestr);

    diff = difftime(standard, daylight);

    printf("Difference is %f hour(s)", diff/60.0/60.0);

    return 0;
}

这会产生:

Difference is 1.000000 hour(s)

两者都是2012年11月4日凌晨1:30,但两者都是两个不同的time_t值,相隔1小时。

mktime()基本上有2个输出:

  • time_t的
  • 修复时间结构

时间结构既是输入又是输出。它由mktime()修改,以将所有结构成员返回到标称范围。例如,如果增加tm_hour成员+= 500,则意味着将时间增加500小时。 tm_hour成员将更改为值00到23,tm_daytm_mday等将全部相应调整。 tm_isdst也是输入和输出。其价值如下:

  • 1(DST有效,即白天时间)
  • 0(DST无效,即标准时间)
  • -1(未知的DST状态)

因此mktime()将为tm_isdst输出1或0,从不输出-1。

-1是一个可能的输入,但我认为它意味着“未知”。不要将其视为“自动确定”,因为通常mktime()不能自动确定它。

显式DST状态(0或1)应来自软件外部的某些内容,例如将其存储在文件或数据库中,或提示用户。

答案 1 :(得分:4)

我认为最初的原因是某些时区没有夏令时。由于mktime不是异步安全的,也不是可重入的,因此允许实现将夏令时的当前值存储在POSIX extern char tzname [2]中,由daylight [0或1]索引。这意味着tzname [0] =“[std TZ name]”和tzname =“[daylight TZ name,例如EDT]”

有关详细信息,请参见tzset()手册页。符合mktime()的标准要求表现得好像无论如何都要调用tzset()。这种情况避免了使用tm_isdst,IMO。

底线:您的特定实现和时区将决定是否对tm_isdst使用-1,0或1。对于所有实现,没有一种默认的正确方法。

答案 2 :(得分:0)

我认为您确实应该在-1字段中使用tm_isdst,除非您掌握有关处理时间类型的信息。

例如,在加利福尼亚州,我们仍然有PST和PDT。如果要解析日期,并且存在时区信息,则应相应设置tm_isdst。正如吉姆·麦克纳马拉(Jim McNamara)所述,在调用tzname[]之后,这些名称在tzset()数组中可用。

例如,以下C ++代码编写PST/PDT

int main(int argc, char * argv [])
{
    tzset();
    std::cerr << tzname[0] << "/" << tzname[1] << "\n";

    return 0;
}

tzname[]数组中的偏移量对应于tm_isdst的值。 (PST-太平洋标准时间tm_isdst = 0,以及PDT,太平洋夏令时间tm_isdst = 1。)

如果输入中没有时区信息,则使用-1是最佳选择。当日期对应于发生更改的日期和时间时,您只会遇到问题。正如Rich Jahn所解释的那样,在2012年11月4日,他在标准时间和夏令时之间进行了更改,并且在该时间前后,gmtime()必须做出选择,这与您期望的相反。话虽这么说,一年中和半夜总共只发生2个小时。因此,除非您使用的是日期非常重要的关键类型的软件,否则可能不会有太大关系。

所以,作为回顾:

  • 如果您要转换的日期附有时区,请使用该信息来确定tm_isdst的值(也就是说,我不太确定如何处理该情况)支持所有时区... tzname[]数组仅为您提供用户的当前时区。)
  • 在所有其他情况下,请使用-1