我想用简单程序做的是计算两个日期之间的秒数差异。
time_t referenceDate;
time_t dateNow = time(0);
struct tm referenceDateComponent = {0};
referenceDateComponent.tm_hour = 0;
referenceDateComponent.tm_min = 0;
referenceDateComponent.tm_sec = 0;
referenceDateComponent.tm_year = 89;
referenceDateComponent.tm_mon = 11;
referenceDateComponent.tm_mday = 31;
referenceDate = mktime(&referenceDateComponent);
long seconds = difftime(dateNow, referenceDate);
使应用程序上方的代码正常工作,但如果尝试设置tm.year
为负(在1900之前构建日期),则mktime()
函数返回-1
我知道time_t
类型根据文档仅管理自1970年1月1日UTC开始的日期:
由于历史原因,它通常被实现为表示自UTC时间1970年1月1日00:00(即,unix时间戳)以来经过的秒数的整数值。尽管库可以使用替代时间表示来实现此类型。
我知道还有Boost
库,但对我来说不是一个有用的解决方案。
所以我的问题是,从1970年以前的日期开始,有什么办法可以在几秒钟之内得到改变?
答案 0 :(得分:8)
我建议使用C ++ 11 std::chrono
命名空间和<chrono>
标准标头以及它们内部的标准函数和类。
您可能还会考虑C标准中的difftime和localtime&amp; mktime
至少要升级到C++11 还有很多其他理由(如果可以的话,还是C++14)。最近几个好的免费软件编译器GCC和Clang/LLVM支持该标准(如果你想要GNU扩展和C ++ 14,可以用-std=c++11
或-std=gnu++14
编译)
BTW,我不确定 Boost 或C ++ 11 <chrono>
是否可以可靠地处理此类日历问题。
答案 1 :(得分:1)
您已经回答了这个问题。 time_t
表示自UNIX纪元以来的秒数,而不是自此之前的任意时间以来的秒数。从根本上说你要做的事情毫无意义。
如果您坚持使用C ++ 03,不管您对可以使用和不能使用的内容的含糊不清,都必须使用Boost.DateTime。
否则,标准库在<chrono>
中有一些很好的现代计时功能。
答案 2 :(得分:1)
当您尝试使用time_t
进行日历算法时,您自然不得不担心time_t
的类型和表示,这当然是实现定义的。它几乎总是一个有符号的整体类型。在Unix和现代MacOS系统上,它自1970年以来只有几秒钟,而且为了兼容性,我认为它也可以在Windows上以这种方式使用。它往往是32位。总而言之,它通常代表1901年12月13日至2038年1月18日之间的日期。
确实当我将代码中的tm_year
行更改为
referenceDateComponent.tm_year = 60;
代码工作并打印1721200226,约为19921天或54。5年,这正是1960年12月31日至今的差异。
但是,如果您将tm_year
设为否定,那么您需要在1900年之前申请某个日期,并且使用time_t
我们的time_t
的典型定义无效#39;一直在讨论。
(tm_year
还有其它可能性。它可能是浮点数。它可以是无符号而不是有符号。它可以是64位类型,这意味着它是&#39; d有大约600,000,000,000年的范围,偶然超过32位time_t
可以容纳。)
所以虽然这里有几个反对者告诉你不要,虽然有很多模糊的困难与时区和闰秒以及Gregorian以外的日历有关,但你通常可以使用{{1}为20世纪和本世纪的日期做基本的日历数学,直到2038年臭名昭着的&#34; Y2.038K problem&#34;会打。 (我担心,它会比不那么臭名昭着的Y2K problem更糟糕,但那是另一个故事。)
正如我所说,你的代码在1970年以前的日期适用于我。以下是我推荐用于基于time_t
的简单日期计算的内容(以及已经提到过的警告):
time_t makedate(int year, int month, int day)
{
struct tm tm = {0};
tm.tm_hour = 12;
tm.tm_min = tm.tm_sec = 0;
tm.tm_year = year - 1900;
tm.tm_mon = month - 1;
tm.tm_mday = day;
tm.tm_isdst = -1;
return mktime(&tm);
}
int main()
{
long int d = difftime(makedate(2015, 7, 17), makedate(2015, 6, 1));
printf("%ld sec = %ld days = %.2f years\n", d, d/86400, d/86400./365.25);
d = difftime(makedate(2015, 7, 17), makedate(2014, 7, 17));
printf("%ld sec = %ld days = %.2f years\n", d, d/86400, d/86400./365.25);
d = difftime(makedate(1975, 7, 17), makedate(1965, 7, 17));
printf("%ld sec = %ld days = %.2f years\n", d, d/86400, d/86400./365.25);
d = difftime(makedate(1950, 1, 11), makedate(1925, 1, 1));
printf("%ld sec = %ld days = %.2f years\n", d, d/86400, d/86400./365.25);
d = difftime(makedate(2030, 12, 31), makedate(2025, 12, 31));
printf("%ld sec = %ld days = %.2f years\n", d, d/86400, d/86400./365.25);
}
就像你的代码一样,它利用了令人惊讶的强大mktime
函数,可以做它可以做的一切。它处理闰年,没问题。它不处理闰秒或日历更改。
如果按照你说的那样,你对1900年以前的日期感兴趣,我恐怕你运气不好。 time_t
根本无法在大多数系统上代表这些日期,因此您将不得不寻求其他解决方案。