另一个关于mktime和DST的问题
Linux、Ubuntu、时区设置为欧洲/柏林,即当前时间为CEST:
>date
Mon Aug 22 16:08:10 CEST 2016
>date --utc
Mon Aug 22 14:08:14 UTC 2016
字符串
目前为止一切顺利。
现在我尝试运行以下代码:
#include <stdio.h>
#include <time.h>
int main()
{
struct tm tm = {0};
int secs;
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;
tm.tm_isdst = 0;
secs = mktime(&tm);
printf("%i\n", secs);
tm.tm_isdst = 1;
secs = mktime(&tm);
printf("%i\n", secs);
tm.tm_isdst = -1;
secs = mktime(&tm);
printf("%i\n", secs);
return 0;
}
型
然后得到
1475233200
1475233200
1475233200
型
这在所有三种情况下都是错误的(1小时偏移):
>date -d @1475233200
Fri Sep 30 13:00:00 CEST 2016
型
所以我现在有点困惑,我的时区不知何故被打破了吗?为什么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;
}
型
给予
1475233200
1475229600
1475229600
型
2条答案
按热度按时间irlmq6kh1#
我想我现在可以看到人们如何发现这一点令人困惑。将
mktime()
视为具有签名字符串
其中
time_t
结果是基于(归一化的)*src
计算的,并且归一化的字段以及当时是否应用夏令时被保存到*dst
。只是C语言开发人员在历史上选择只使用一个指针,将
src
和dst
组合在一起。但上述逻辑仍然成立。请参阅
man mktime
手册页,尤其是以下部分:函数的作用是:将分解的时间结构(表示为本地时间)转换为日历时间表示。该函数忽略调用方在tm_wday和tm_yday字段中提供的值。tm_isdst字段中指定的值通知mktime()夏令时(DST)是否在tm结构中提供的时间内生效:正值表示DST有效; 0表示DST未生效;负值意味着mktime()应该(使用时区信息和系统数据库)尝试确定DST是否在指定时间生效。
mktime()函数修改tm结构的字段如下:tm_wday和tm_yday被设置为根据其它字段的内容确定的值;如果结构成员超出其有效间隔,则将对其进行规范化(例如,将10月40日更改为11月9日); tm_isdst分别被设置(不管其初始值如何)为正值或0,以指示DST在指定时间是否生效。调用mktime()还将使用有关当前时区的信息设置外部变量tzname。
如果指定的分解时间不能表示为日历时间(从Epoch开始的秒数),mktime()返回(time_t)-1,并且不改变分解时间结构的成员。
换句话说,如果你稍微改变一下你的测试程序,比如说变成
型
然后运行它会产生输出
型
换句话说,它的行为完全如所描述的(在上面的引用中)。这种行为在C89、C99和POSIX. 1中都有记录(我想C11也有,但没有检查)。
aij0ehis2#
成功完成后,结构的
tm_wday
和tm_yday
组件的值将被适当设置,其他组件将被设置为表示指定的日历时间,... C11dr §7.27.2.3 2调用
mktime(&tm)
时,tm
的原始值不受范围限制。由于第一个
mktime(&tm)
调用,当然tm.tm_isdst
和tm.tm_hour
被调整为1和11。所以OP的以下代码tm.tm_isdst = 1;
和tm.tm_isdst = -1;
不会影响时间戳。最好设置所有字段进行调查。
字符串