将tm_hour设为0后dateplusdays函数加天操作异常的原因排查
日期加天数函数的夏令时异常原因分析
以下是实现yyyymmdd格式日期加天数功能的dateplusdays函数:
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); // 将i转换为有效日期 if (i == a) { // 验证是有效日期 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后,1900-2100区间出现184个特定日期错误,例如2022年10月30日加1天仍为当天,错误集中在9-11月:
geohei@vm92:~/Devel$ ./dateplusdays | cut -c7-8 | sort | uniq -c 47 09 131 10 6 11
异常原因
这个问题是**夏令时(DST,Daylight Saving Time)**切换导致的:
- 当
tm_hour设为0时,对应日期的午夜0点。在夏令时结束的日期(比如北半球部分地区的10月最后一个周日),时钟会从凌晨2:00回拨到1:00,这一天实际有25个小时。 - 此时给该日期的0点加上86400秒(24小时),实际只走到了当天的23:00(因为有1小时的时间重复),所以
localtime解析后得到的仍然是当天的日期,出现加1天却日期不变的错误。 - 而将
tm_hour设为12点时,这个时间点避开了夏令时切换的凌晨窗口,加24小时后必然进入下一天,不会触发这个问题。
错误集中在9-11月,正是北半球夏令时结束的时间段,回拨调整导致当天时长超过24小时,从而引发计算异常。
内容的提问来源于stack exchange,提问作者geohei
相关产品推荐
相关产品推荐

