c++ - std::chrono:将时钟的纪元设置为 1/1/0000

标签 c++ c++11 epoch c++-chrono

是否可以手动将纪元日期/时间设置为 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/

相关文章:

c++ - python 代码中的 SwigPyObject 和 JSON 通信

c++ - 在 qt5 中使用 QSharedPointers 时出现段错误

c++ - 决策、复杂条件和规划易于维护

c++ - 使用 QML 绘制图形项目的最佳方式是什么?

C++11:字符串文字的类型是 "array of the appropriate number of const characters"

c++ - std::remove_if 是否保证按顺序调用谓词?

python - 在 Python 中将 datetime.datetime 对象转换为自纪元以来的天数

C++:将基类型完美透明地包装到一个类中?

java - 在 Android 中将纪元时间转换为日期并将日期转换为纪元时间

datetime - 为什么同一时间的 Unix 时间戳在不同时区是不同的