如何使“ days-since-epoch”值与std :: chrono配合使用?

ein*_*ica 2 c++ c++-chrono

我从一个神奇的gremlin中获得了内存中非负整数值的数组,例如type I。这些中的每一个都代表某个时期以来的天数(在ISO 8601日历中,该时间比0早许多年)。

现在,我想用C ++类包装这些值(基本上是通过指针或重新解释),它们可以与的代码很好地交互std::chrono,或者也许我应该说将它们与通常需要std::chrono时间点和持续时间的代码一起使用。

为此,我最好的做法是什么?注意我不想替换数组中的任何数据,也不想为其他地方的每个现有数据创建新值。

How*_*ant 7

这些中的每一个都代表该纪元以来的天数(在ISO 8601日历中,该时间比0早许多年)。

假设您指的是儒略日数的时代。此时期与您的描述一致。链接上说这个时期是公元前4714年11月24日。我发现不使用“ BC”系统,而是使用负数年的系统比较方便,这样在0年中就可以进行平滑的数学转换。在这个系统中,纪元是11月24日,-4713。

使用Howard Hinnant的免费,开放源代码,仅标头的日期库,这很容易做到。如果我的时代错误,只需在明显的地方替换正确的时代。

#include "date/date.h"
#include <iostream>

date::sys_days
to_sys_days(int i)
{
    using namespace date;
    return sys_days{days{i} -
        (sys_days{1970_y/January/1} - sys_days{-4713_y/November/24})};
}
Run Code Online (Sandbox Code Playgroud)

date::sys_days返回类型是std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<int, std::ratio<86400>>>。或用英语:它是system_clock基于的time_point,精度为days。这time_point将隐式转换为您平台的system_clock::time_point

现在,您可以将传递intto_sys_days,并将结果传递给带有的函数system_clock::time_point。例如:

void
display(std::chrono::system_clock::time_point tp)
{
    using date::operator<<;
    std::cout << tp << '\n';
}

int
main()
{
    display(to_sys_days(2'458'674));
}
Run Code Online (Sandbox Code Playgroud)

输出:

2019-07-09 00:00:00.000000
Run Code Online (Sandbox Code Playgroud)

to_sys_days非常便宜的操作。每次读取数据的单个元素时,您都可以负担得起。它所做的就是从中减去2440588 ito_sys_days(clang ++ -O3)的优化机器代码从字面上看是:

leal    -2440588(%rdi), %eax
Run Code Online (Sandbox Code Playgroud)

即所有类型更改业务都发生在编译时。免费。在运行时发生的唯一事情是时间偏移调整。无论将纪元与system_clock纪元对齐,这都是必须完成的最低要求。

因此,如果您有一个数组int作为数据,则不必复制整个数组。您只需按需转换它的每个元素。例如:

int
main()
{
    int data[] = {2'458'674, 2'458'675, 2'458'676, 2'458'677, 2'458'678};
    for (auto i : data)
        display(to_sys_days(i));
}
Run Code Online (Sandbox Code Playgroud)

输出:

2019-07-09 00:00:00.000000
2019-07-10 00:00:00.000000
2019-07-11 00:00:00.000000
2019-07-12 00:00:00.000000
2019-07-13 00:00:00.000000
Run Code Online (Sandbox Code Playgroud)

如果您不想使用日期库,仍然可以完成工作,这只是更多的工作。

首先创建一个duration表示天数的类型:

using days = std::chrono::duration
    <int, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;
Run Code Online (Sandbox Code Playgroud)

然后计算出从1970-01-01到您的纪元之间的天数。

然后取您的整数值i,将其包装起来days,然后减去历元差。然后,您可以system_clock::time_point使用的值构造一个days

注意:重要的是您要以单位进行历元调整,days而不是先转换为system_clock::time_point,然后再进行调整。后一种策略将在某些平台上溢出。如果days精确地进行历元偏移,则可以防止溢出。


我强烈建议您不要使用该reinterpret_cast工具来完成这项工作。似乎既不必要又危险。


更新资料

我忘了说朱利安纪念日时代是中午而不是午夜的部分。如果要考虑到这一点,可以使用日期lib来轻松实现:

auto
to_sys_days(int i)
{
    using namespace date;
    using namespace std::chrono;
    return sys_time<hours>{days{i} -
        (sys_days{1970_y/January/1} - sys_days{-4713_y/November/24} - 12h)};
}
Run Code Online (Sandbox Code Playgroud)

我只是简单地减去了时差12小时,然后auto为我推断出返回类型(现在是system_clock基于- time_point,精度为hours)。

完全相同的display以相同的输入输出现在功能:

2019-07-09 12:00:00.000000
Run Code Online (Sandbox Code Playgroud)