问题 mktime和tm_isdst


我在这里想到了很多不同的看法。

我读 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 让系统决定它的dst是否与代码成为dst不可知?

我错过了什么吗?


2467
2017-12-19 08:50


起源



答案:


我认为最初的原因是某些时区没有夏令时。由于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。对于所有实现,没有一种默认的正确方法。


4
2017-12-19 18:24





如果可能,您应该避免将tm_isdst设置为-1。系统无法始终仅从日期和时间确定DST状态。在夏令时结束之前和之后的一小时,这是模棱两可的。例如,如果你通过 mktime() 2012年11月4日凌晨1:30,这还不足以让您获得正确的信息 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() 将所有struct成员返回到名义范围。例如,如果增加tm_hour成员 += 500,这意味着将时间增加500小时。该 tm_hour 会员将更改为值00到59,并且 tm_daytm_mday等都将相应调整。 tm_isdst 也是输入和输出。其价值如下:

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

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

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

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


9
2017-08-24 18:49



好吧,如果你不知道DST,你需要自己确定(祝你好运),或者设置它 -1。没有其他选择。如果你把它设置为0,你就不会得到任何保证错误的DST,如果你把它设置为1你强制DST也保证错误。 - rustyx
@RustyX硬编码为-1,0或1总是错误的。 -1是最不好的,但仍然很糟糕。显式状态(0或1)应该是 输入 从用户到软件,或存储在数据(文件或数据库)中。基本上它必须来自应用程序外部的东西。 - Rich Jahn
v很好的答案。谢谢 - drlolly
@RichJahn:它存储在一个数据库中:关于每个UNIX / Linux系统的TZ数据库。关于在任何给定时间从那里检索它的最简单方法是执行mktime并将tm_isdst设置为-1 ...并且你还记得DST更改发生的时间吗?要求用户提供此信息并不合理。 “你应该避免将tm_isdst设置为-1 如果可能的话。“ - 在什么样的合理,常见的使用场景中有可能吗? - SF.
@SF。我的全部观点是“它”不存储在任何地方。电脑不知道。通过类比,如果我说:绝对值是5,原始数字是正数还是负数?你不能写一个程序来解决这个问题,除非它是一个思维阅读程序。答案是:我不知道,你告诉我。我知道2017年11月5日午夜是美国CDT,而上午5点是美国科技委员会。但凌晨1:30?我不知道,你告诉我。我编写的应用程序会使其成为致命错误,或者如果时间不明确则提示用户。我认为大多数日期选择器UI完全忽略了这个问题。 - Rich Jahn


答案:


我认为最初的原因是某些时区没有夏令时。由于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。对于所有实现,没有一种默认的正确方法。


4
2017-12-19 18:24





如果可能,您应该避免将tm_isdst设置为-1。系统无法始终仅从日期和时间确定DST状态。在夏令时结束之前和之后的一小时,这是模棱两可的。例如,如果你通过 mktime() 2012年11月4日凌晨1:30,这还不足以让您获得正确的信息 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() 将所有struct成员返回到名义范围。例如,如果增加tm_hour成员 += 500,这意味着将时间增加500小时。该 tm_hour 会员将更改为值00到59,并且 tm_daytm_mday等都将相应调整。 tm_isdst 也是输入和输出。其价值如下:

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

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

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

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


9
2017-08-24 18:49



好吧,如果你不知道DST,你需要自己确定(祝你好运),或者设置它 -1。没有其他选择。如果你把它设置为0,你就不会得到任何保证错误的DST,如果你把它设置为1你强制DST也保证错误。 - rustyx
@RustyX硬编码为-1,0或1总是错误的。 -1是最不好的,但仍然很糟糕。显式状态(0或1)应该是 输入 从用户到软件,或存储在数据(文件或数据库)中。基本上它必须来自应用程序外部的东西。 - Rich Jahn
v很好的答案。谢谢 - drlolly
@RichJahn:它存储在一个数据库中:关于每个UNIX / Linux系统的TZ数据库。关于在任何给定时间从那里检索它的最简单方法是执行mktime并将tm_isdst设置为-1 ...并且你还记得DST更改发生的时间吗?要求用户提供此信息并不合理。 “你应该避免将tm_isdst设置为-1 如果可能的话。“ - 在什么样的合理,常见的使用场景中有可能吗? - SF.
@SF。我的全部观点是“它”不存储在任何地方。电脑不知道。通过类比,如果我说:绝对值是5,原始数字是正数还是负数?你不能写一个程序来解决这个问题,除非它是一个思维阅读程序。答案是:我不知道,你告诉我。我知道2017年11月5日午夜是美国CDT,而上午5点是美国科技委员会。但凌晨1:30?我不知道,你告诉我。我编写的应用程序会使其成为致命错误,或者如果时间不明确则提示用户。我认为大多数日期选择器UI完全忽略了这个问题。 - Rich Jahn