我会std::time_t
完全避免。使用days_from_civil
from chrono-Compatible Low-Level Date Algorithmsstd::chrono::system_clock::time_point
,您可以立即计算, 和预测公历1中的任何日期之间的任何差异。
除了days_from_civil
需要年/月/日三元组并将其转换为 1970-01-01 之前/之后的天数(与计时兼容的纪元)之外,还可以方便地创建一个自定义chrono::duration
来表示 24 小时:
typedef std::chrono::duration
<
int,
std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>
> days;
现在你可以创建任何你想要的时代:
constexpr days epoch = days(days_from_civil(0, 1, 1)); // 0000-01-01
在 C++1y 中,这甚至是编译时计算!
你可以std::chrono::duration
从任何其他中减去这个std::chrono::duration
:
auto delta = std::chrono::system_clock::now().time_since_epoch() - epoch;
delta
现在是std::chrono::duration
表示从现在到 0000-01-01 之间的时间量。然后,您可以根据需要将其打印出来,或以其他方式对其进行操作。例如,这是一个完整的工作演示:
#include "../date_performance/date_algorithms"
#include <iostream>
#include <chrono>
typedef std::chrono::duration
<
int,
std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>
> days;
int
main()
{
constexpr days epoch = days(days_from_civil(0, 1, 1));
auto delta = std::chrono::system_clock::now().time_since_epoch() - epoch;
days d = std::chrono::duration_cast<days>(delta);
std::cout << "It has been " << d.count() << " days, ";
delta -= d;
auto h = std::chrono::duration_cast<std::chrono::hours>(delta);
std::cout << h.count() << " hours, ";
delta -= h;
auto m = std::chrono::duration_cast<std::chrono::minutes>(delta);
std::cout << m.count() << " minutes, ";
delta -= m;
auto s = std::chrono::duration_cast<std::chrono::seconds>(delta);
std::cout << s.count() << " seconds ";
std::cout << " since 0000-01-01\n";
}
对我来说输出:
It has been 735602 days, 19 hours, 14 minutes, 32 seconds since 0000-01-01
关于溢出的警告:
std::chrono::system_clock::time_point::duration
不保证有足够大的范围来执行此操作。事实证明,在我的系统上确实如此。它是一个有符号的 long long 中的微秒,它将跨越 +/- 292,000 年。如果您需要避免溢出问题,您可以std::chrono::system_clock::time_point::duration
在减去 0000-01-01 之前将您的单位截断为更粗略的单位(例如秒或天)以扩大范围。
我开始思考
这通常会导致灾难。但是在这种情况下,我决定无论如何我都应该添加到这篇文章中。这个:
constexpr days epoch = days(days_from_civil(0, 1, 1));
有类型days
,这是一个duration
。但它确实不是一个duration
. 这是一个时间点。这是一个约会。这是time_point
一个粗略的精度。通过引入一个新的 typedef,这篇文章中的代码可以稍微清理一下:
typedef std::chrono::time_point<std::chrono::system_clock, days> date_point;
现在而不是写:
constexpr days epoch = days(days_from_civil(0, 1, 1));
可以写:
constexpr date_point epoch{days(days_from_civil(0, 1, 1))};
但更重要的是,而不是:
auto delta = std::chrono::system_clock::now().time_since_epoch() - epoch;
我们现在可以写:
auto delta = std::chrono::system_clock::now() - epoch;
这delta
仍然具有与以前完全相同的类型和值,并且演示中的其他所有内容仍然与以前完全相同。
这既是一个小变化,也是一个大变化。通过将's 和'的代数epoch
视为 atime_point
而不是 a ,我们可以简化和检查我们的表达式,以帮助我们编写更简洁的代码和更少的错误。duration
time_point
duration
例如,可以将两个duration
' 加在一起。但这根本没有任何意义:
epoch + epoch
通过使用time_point
而不是duration
for 的类型epoch
,编译器会在编译时捕获此类无意义的表达式。
1预测的公历有 0 年。在 0 年,它比儒略历晚 2 天。使用第 0 年也符合 ISO 8601。只要所有相关方都知道您使用的是什么日历,那么一切都很好。如果需要,非正数年和“BC 年”之间的转换是微不足道的。