c++ - 如何使“days-since-epoch”值与 std::chrono 配合得很好?
问题描述
我从一个神奇的 gremlin 获取内存中非负整数值的数组,比如 type I
。这些中的每一个都代表自某个时期以来的天数(在 ISO 8601 日历中的 0 之前很多年)。
现在,我想用 C++ 类包装这些值 - 主要是通过指针或重新解释 - 它可以与 的代码很好地交互std::chrono
,或者我应该说与通常需要std::chrono
时间点和持续时间的代码一起使用。
对此,我最好的做法是什么?请注意,我不想替换数组中的任何数据,也不想在其他地方为每个现有数据创建新值。
解决方案
这些中的每一个都代表自纪元以来的天数(在 ISO 8601 日历中的 0 之前很多年)。
假设您指的是Julian Day Number的时代。这个时代与你的描述一致。链接说这个时代是公元前 4714 年 11 月 24 日,在公历中。我发现不使用“BC”系统,而是使用带有负年份的系统更方便,以便在第 0 年有一个平滑的数学过渡。在这个系统中,纪元是 -4713 年 11 月 24 日。
使用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})};
}
date::sys_days
返回类型是std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<int, std::ratio<86400>>>
a 。或者用英语:它是system_clock
基于- 的time_point
,精度为days
。这time_point
将隐式转换为您平台的system_clock::time_point
.
现在您可以将您的to 传递int
给to_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));
}
这输出:
2019-07-09 00:00:00.000000
to_sys_days
是一个非常便宜的手术。每次读取数据的单个元素时,您都可以负担得起。它所做的只是从 中减去 2440588 i
。to_sys_days
(clang++ -O3)的优化机器代码字面意思是:
leal -2440588(%rdi), %eax
即所有的类型更改业务都发生在编译时。免费。运行时唯一发生的事情是纪元偏移调整。这是无论要使您的时代与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));
}
输出:
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
如果您不想使用日期库,您仍然可以完成工作,只是多做一点工作。
首先创建一个duration
表示天数的类型:
using days = std::chrono::duration
<int, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;
然后计算 1970-01-01 和您的时代之间的天数。
然后取你的积分值i
,把它包起来days
,然后减去你的时代差异。然后你可以system_clock::time_point
用你的值构造 a days
。
注意:重要的是您以 为单位进行历元调整,days
而不是先转换为单位system_clock::time_point
然后再进行调整。后一种策略会在某些平台上溢出。如果您days
精确地进行纪元偏移,则可以防止溢出。
我强烈建议不要使用该reinterpret_cast
工具来完成这项工作。这似乎既不必要又危险。
更新
我忘了说儒略日时代是中午而不是午夜的部分。如果您想考虑到这一点,使用日期库非常容易:
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)};
}
我只是从 epoch 差异中减去 12 小时,然后auto
为我推断返回类型(现在是system_clock
基于- 的time_point
,精度为hours
)。
具有相同输入的完全相同的display
函数现在输出:
2019-07-09 12:00:00.000000
推荐阅读
- apache - 在 Windows 上将 sed 与 Apache 一起使用时,管道日志程序意外失败
- javascript - 如何将随机颜色应用于每个字母而不是单词?
- python - Python相当于Spark rangeBetween for window?
- java - Aparapi:不调用 GPU
- database - FILTER 语句的顺序是否会影响 arangoDB 中查询的性能?
- node.js - 更改 express 中的最大查询字符串长度
- synchronization - Unison 使用 rootalias 移动根目录
- android - 键盘可见时移动按钮
- excel - 使用 DAX 公式将文本显示为值 Power Pivot
- javascript - 如何显示没有属性名称的数据