使用下面的函数,简单地将天数添加到日期(yyyymmdd),在几年中都能很好地工作。
int dateplusdays(int datein, int days) {
int year, month, day;
int dateout;
struct tm date;
time_t secs;
year = (int)floor(datein / 10000.0);
month = (int)floor(datein / 100.0) - year * 100;
day = datein - month * 100 - year * 10000;
date.tm_sec = 0;
date.tm_min = 0;
date.tm_hour = 12;
date.tm_year = year - 1900;
date.tm_mon = month - 1;
date.tm_mday = day;
date.tm_isdst = -1;
secs = mktime(&date) + days * 86400;
date = *localtime(&secs);
dateout = (date.tm_year + 1900) * 10000 + (date.tm_mon + 1) * 100 + date.tm_mday;
return dateout;
}
我用这个测试代码从1900到2100进行了压力测试。没有错误!
for (i = 19000101; i < 21001231; i++) {
int a = dateplusdays(i, 0); // make date out of i
if (i == a) { // check for valid date
int b = dateplusdays(a, 1);
int c = dateplusdays(b, 1);
if (b == c)
printf("i:%d a:%d b:%d c:%d\n", i, a, b, c);
}
}
现在......当将date.tm_hour
从12
更改为0
时,我在非常特定的日期上得到了184个错误,这些错误完全不规则地分布在1900 - 2100年的范围内(例如,30.10.2022加上1天会得到30.10.2022)。
i:19160930 a:19160930 b:19161001 c:19161001
i:19161001 a:19161001 b:19161001 c:19161001
...
i:20221029 a:20221029 b:20221030 c:20221030
i:20221030 a:20221030 b:20221030 c:20221030
...
i:20381030 a:20381030 b:20381031 c:20381031
i:20381031 a:20381031 b:20381031 c:20381031
最重要的是,只关注9月至12月。
geohei@vm92:~/Devel$ ./dateplusdays | cut -c7-8 | sort | uniq -c
47 09
131 10
6 11
我错过了什么?
1条答案
按热度按时间dwbf0jvd1#
您错过了冬季和夏季时间之间的切换-标准时间和夏令时,或者使用任何其他术语。选择
12:00:00
作为一天中的时间并不是偶然的。你应该使用
date.tm_day = day + days;
来得到正确的答案(而不是加上days * 86400
)。mktime()
函数将日期标准化。注意,在某些日子里有82800秒和90000秒,这是因为从UTC切换到了时区偏移量。旁注:你到底为什么要用浮点数而不是整数除法呢?
嗯:我尝试了你的代码与最低限度的额外(头部,一个实际的
main()
函数),只有得到输出时,我改变了12
在代码中的0
-运行在MacBook Pro与macOS大苏尔11.7.2。你引用的日期接近10月底,时钟“回落”的时候。夏令时于1918年在美国首次引入,1921年后停止。1945年重新引入一年,然后在1965年“永久”。规则在1991年改变,所以秋季时间开关从“10月的最后一个星期日”改为“11月的第一个星期日”,所以我从你身上看到了不同的价值观。(Spring时间转换的规则也同时从“四月的第一个星期天”变成了“三月的第二个星期天”。)我猜你住在北美以外的地方(或者至少在美国以外)。
下面是一些修改过的代码,利用了
mktime()
的能力,使用了midnight。它还使用ISO 8601符号来格式化数据。但是,除非使用-DUSE_BROKEN_CODE
作为编译时选项进行编译,否则它不会产生任何输出。我住在美国科罗拉多州,所以当我编译这个程序时,我得到了这样的结果: