是否可以手动将纪元日期/时间设置为 0000 年 1 月 1 日,以便我可以使用 std::chrono::time_point::time_since_epoch 来计算给定日期与 0000 年 1 月 1 日之间的差异?
我尝试了以下方法:
#include <iostream>
#include <chrono>
#include <ctime>
int main(int argc, char*argv[])
{
std::tm epochStart = {};
epochStart.tm_sec = 0;
epochStart.tm_min = 0;
epochStart.tm_hour = 0;
epochStart.tm_mday = 0;
epochStart.tm_mon = 0;
epochStart.tm_year = -1900;
epochStart.tm_wday = 0;
epochStart.tm_yday = 0;
epochStart.tm_isdst = -1;
std::time_t base = std::mktime(&epochStart);
std::chrono::system_clock::time_point baseTp=
std::chrono::system_clock::from_time_t(base);
std::time_t btp = std::chrono::system_clock::to_time_t(baseTp);
std::cout << "time: " << std::ctime(&btp);
}
但这给了我
time: Thu Jan 1 00:59:59 1970
最佳答案
我会避免 std::time_t
共。使用 days_from_civil
来自 chrono-Compatible Low-Level Date Algorithms ,您可以立即计算出 std::chrono::system_clock::time_point
之间的任何差异,以及 proleptic Gregorian calendar 中的任何日期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
不能保证有足够大的范围来做到这一点。事实证明,在我的系统上确实如此。它是 signed long long 中的微秒,跨越 +/- 292,000 年。如果你需要避免溢出问题,你可以截断你的 std::chrono::system_clock::time_point::duration
在减去 0000-01-01 之前以类(class)单位(例如秒或天)扩展范围。
我开始思考
这通常会导致灾难。但是在这种情况下,我决定无论如何我都应该添加到这篇文章中。这:
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
仍然具有与以前完全相同的类型和值,并且演示中的其他所有内容仍然像以前一样进行。
这既是一个小变化,也是一个大变化。通过治疗epoch
作为 time_point
而不是 duration
, time_point
的代数的和duration
对我们有用,既简化了表达式的也类型检查,以帮助我们编写更清晰的代码,错误更少。
例如一个可以加两个duration
在一起了但这根本没有任何意义:
epoch + epoch
通过使用 time_point
而不是 duration
对于 epoch
的类型,编译器会在编译时捕获此类无意义的表达式。
1proleptic Gregorian calendar有 0 年。在 0 年,它比儒略历晚 2 天。使用 0 年也符合 ISO 8601。只要所有相关方都知道您使用的是什么日历,那么一切都很好。如果需要,非正年份和“BC 年份”之间的转换是微不足道的。
关于c++ - std::chrono:将时钟的纪元设置为 1/1/0000,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20923612/