这是一个奇怪的情况。查看this Coliru code:
#include <iostream>
#include <utility>
#include <ctime>
using namespace std;
#define SEGS 60
#define MINS 60
#define HOURS 24
int days(tm* date1, tm* date2)
{ return (mktime(date1) - mktime(date2)) / SEGS / MINS / HOURS; }
tm mkdate(int day, int mon, int year)
{
tm date = {0, 0, 0};
date.tm_mday = day;
date.tm_mon = mon - 1;
date.tm_year = year - 1900;
return date;
}
int main()
{
tm date1 = mkdate(31, 12, 2030);
tm date2 = mkdate(1, 1, 2000);
cout << days(&date1, &date2) << endl;
// 11322... OK 30 * 365 (1/1/2000 - 1/1/2030)
// + 8 (leap years) + 364 (from 1/1/2030 - 31/12/2030).
date1 = mkdate(31, 12, 2030);
date2 = mkdate(1, 1, 1930);
cout << days(&date1, &date2) << endl;
// 36889... OK; but in my machine, it returns 36888.
date1 = mkdate(31, 12, 1943);
date2 = mkdate(1, 1, 1943);
cout << days(&date1, &date2) << endl;
// 364... OK: but in my machine, it returns 363.
date1 = mkdate(30, 6, 1943);
date2 = mkdate(1, 6, 1943);
cout << days(&date1, &date2) << endl;
// 29... OK; but in my machine, it returns 28.
date1 = mkdate(27, 6, 1943);
date2 = mkdate(26, 6, 1943);
cout << days(&date1, &date2) << endl;
// 1... OK; but in my machine, it returns 0.
return 0;
}
每个示例后的评论均来自Coliru和我的笔记本电脑。 Coliru输出正确,但是我的机器是谁打印了错误的数字。
如果您阅读该代码,则正确计算了天之间的差额(第一个示例,从2000年1月1日到2030年12月31日)。
但是,如果1943年处于日期间隔的中间,则似乎失去了一天。第二个例子:1/19/1930-20/12/31。
经过大量测试,我发现问题出在Juny / 1943。第三个示例:1/6/1943-30/6/1943,返回28天而不是29天。
更确切地说,似乎26日和27日是同一天。第四个示例:26/6/1943-27/6/1943,返回0天。
我的机器是使用gcc(g++)4.8.2,Linux 3.13.0-52通用x86_64的Ubuntu 14.02.2 LTS。
问题出在哪里? GNU libc实现的某种错误?
最佳答案
这是一个时区问题。在main()的开头添加以下内容:
// set the timezone to UTC
setenv("TZ", "", 1);
tzset();
同样,您的days()函数应这样编写:
double days (tm *date1, tm *date2) {
return difftime (mktime(date1), mktime(date2)) / 86400;
}
根本原因是time_t代表自UTC纪元以来的秒数,而mktime()将其参数解释为本地时区中的日期。因此,它必须将其转换为UTC以产生time_t。因此,如果本地时区的两个日期之间相对于UTC不连续,则结果可能是错误的。
真正的解决方案是不使用mktime()。它不适用于您的应用程序(除了DST之外,还有其他问题,例如leap秒)。
您要尝试做的是计算(丰满的)公历中两个日期之间的天数。您应该自己实现此目的,例如,将它们转换为儒略日数。
关于c++ - C++和mktime:26/6/1943和27/6/1943是同一天,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30191700/