添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

所以我现在有点疑惑,我的时区是不是有问题?为什么tm_isdst标志被完全忽略?

编辑。@Nominal Animal给出了答案:mktime修改了tm_hour!我想知道它在哪里被记录下来了?

#include <stdio.h>
#include <time.h>
void reset(struct tm* tm){
    (*tm) = (const struct tm){0};
    tm->tm_sec = 0;
    tm->tm_min = 0;
    tm->tm_hour = 12;
    tm->tm_mon = 9 - 1;
    tm->tm_mday = 30;
    tm->tm_year = 2016 - 1900;
int main()
    struct tm   tm;
    int secs;
    reset(&tm);
    tm.tm_isdst = 0;
    secs = mktime(&tm);
    printf("%i\n", secs);
    reset(&tm);
    tm.tm_isdst = 1;
    secs = mktime(&tm);
    printf("%i\n", secs);
    reset(&tm);    
    tm.tm_isdst = -1;
    secs = mktime(&tm);
    printf("%i\n", secs);
    return 0;

gives

1475233200
1475229600
1475229600
    
5 个评论
1)这种行为似乎很奇怪。 对better trouble shoot, reset 所有 fields again (or at least print them) after c所有ing mktime(&tm); as mktime() may adjust the tm fields. 2) Use a matching format specifier like printf("%i\n", (int) secs); or printf("%lld\n", (long long) secs); to avoid undefined behavior.
It might seem奇怪,但它真的不奇怪。的确如此。mktime()修改了它的参数--特别是在这种情况下,tm.tm_hourtm.tm_isdst字段。
@名义上的动物是什么 odd是指mktime()预计不会改变tm,因为tm在前2种情况下处于初级范围。 ahh也许在第一种情况下不是。 嗯--夏天的dst为0,可能会变成1。
@chux 能否请你发布一个答案,以便我接受,这似乎是有效的,这东西真的很奇怪。
@Stasik: mktime()始终tm_isdst改为01。该行为的描述(正如我在答案中解释的那样)是在男子3米长的时间man页,以及更简略的形式in POSIX.1.
c
linux
unix
posix
mktime
Stasik
Stasik
发布于 2016-08-22
2 个回答
Nominal Animal
Nominal Animal
发布于 2016-08-22
已采纳
0 人赞同

我想我现在明白了,人们会觉得这很混乱。把mktime()看作是有签名的

time_t mktime_actual(struct tm *dst, const struct tm *src);

其中time_t的结果是根据(规范化的)*src计算出来的,而规范化的字段和夏令时是否适用于该时间,被保存到*dst

只是C语言的开发者在历史上只选择使用一个指针,把srcdst都结合起来。不过,上述逻辑仍然成立。

See the `man mktimeman页,特别是这一部分。

mktime()函数将一个分解的时间结构转换为当地时间。 表达为本地时间,转换成日历时间表示。 该 函数忽略了调用者在tm_wday和 tm_daily字段中提供的值。 在tm_isdst字段中指定的值会告知 mktime()是否在夏令时(DST)中生效。 中提供的时间是否有效:一个正值意味着DST正在生效;零意味着DST在 正值意味着DST生效;零意味着DST不生效;而负值 意味着mktime()应该(使用时区信息和系统数据库来)尝试确定DST是否生效。 负值表示mktime()应该(使用时区信息和系统数据库)试图确定在指定的时间是否有夏令时生效。 指定的时间是否生效。

mktime()函数对tm结构的字段进行修改,具体如下 如下:tm_wday和tm_daily被设置为由其他字段的内容决定的值。 其他字段的内容决定;如果结构成员超出了其 如果结构成员在其有效区间之外,它们将被归一化(因此,例如,10月40日被改为11月9日 10月被改为11月9日);tm_isdst被设置为(无论其初始值如何)正值。 tm_isdst 被设置为正值或 0,分别表示 DST 是否存在。 表示DST在指定时间是否生效。 调用mktime()还将外部变量tzname设置为关于当前时区的信息。 关于当前时区的信息。

如果指定的分解时间不能被表示为日历时间 时间(自大纪元以来的秒数),mktime()返回(time_t) -1,并且不改变分解时间结构的成员。 并不改变分解时间结构的成员。

换句话说,如果你把你的测试程序改变一下,例如变成

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
static const char *dst(const int flag)
    if (flag > 0)
        return "(>0: is DST)";
    if (flag < 0)
        return "(<0: Unknown if DST)";
        return "(=0: not DST)";
static struct tm newtm(const int year, const int month, const int day,
                       const int hour, const int min, const int sec,
                       const int isdst)
    struct tm t = { .tm_year  = year - 1900,
                    .tm_mon   = month - 1,
                    .tm_mday  = day,
                    .tm_hour  = hour,
                    .tm_min   = min,
                    .tm_sec   = sec,
                    .tm_isdst = isdst };
    return t;
int main(void)
    struct tm   tm = {0};
    time_t secs;
    tm = newtm(2016,9,30, 12,0,0, -1);
    secs = mktime(&tm);
    printf("-1: %04d-%02d-%02d %02d:%02d:%02d %s %lld\n",
           tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
           tm.tm_hour, tm.tm_min, tm.tm_sec, dst(tm.tm_isdst), (long long)secs);
    tm = newtm(2016,9,30, 12,0,0, 0);
    secs = mktime(&tm);
    printf(" 0: %04d-%02d-%02d %02d:%02d:%02d %s %lld\n",
           tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
           tm.tm_hour, tm.tm_min, tm.tm_sec, dst(tm.tm_isdst), (long long)secs);
    tm = newtm(2016,9,30, 12,0,0, 1);
    secs = mktime(&tm);
    printf("+1: %04d-%02d-%02d %02d:%02d:%02d %s %lld\n",
           tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
           tm.tm_hour, tm.tm_min, tm.tm_sec, dst(tm.tm_isdst), (long long)secs);
    return EXIT_SUCCESS;

then running it produces output

-1: 2016-09-30 12:00:00 (>0: is DST) 1475226000
 0: 2016-09-30 13:00:00 (>0: is DST) 1475229600
+1: 2016-09-30 12:00:00 (>0: is DST) 1475226000

换句话说,它的行为与描述的完全一样(在上面的引文中)。这种行为在C89、C99和POSIX.1中都有记载(我想C11也有,但没有检查过)。

chux - Reinstate Monica
chux - Reinstate Monica
发布于 2016-08-22
0 人赞同

成功完成后,结构中的tm_wdaytm_yday组件的值被适当地设置,并且other components被设置为代表指定的日历 时间,... C11dr §7.27.2.3 2

当调用mktime(&tm)时,tm的原始值没有范围限制。

由于第一个mktime(&tm)的调用,当然tm.tm_isdsttm.tm_hour被调整为1和11。所以OP下面的代码tm.tm_isdst = 1;tm.tm_isdst = -1;并没有影响时间戳。

最好将所有字段都设置为调查。

struct tm   tm0 = {0};
struct tm   tm;
int secs;
tm0.tm_sec = 0;
tm0.tm_min = 0;
tm0.tm_hour = 12;
tm0.tm_mon = 9 - 1;
tm0.tm_mday = 30;
tm0.tm_year = 2016 - 1900;
tm = tm0;
tm.tm_isdst = 0;
secs = mktime(&tm);
printf("%i\n", (int) secs);
tm = tm0;
tm.tm_isdst = 1;
secs = mktime(&tm);
printf("%i\n", (int) secs);