繁体   English   中英

C++:地板 unix 时间戳到 UTC 月份

[英]C++: floor unix timestamp to UTC month

假设我有一个 unix 时间戳

int timestamp=1594386202;

我想写一个 function

int floor_to_month_utc(int timestamp);

将时间戳记到相应月份的开始(以 UTC 为单位)。 In this example the function shall satisfy 1593561600 == floor_to_month_utc(1594386202) because 1594386202 corresponds to 2020-07-10T13:03:22+00:00 UTC time and 1593561600 is the beginning of the corresponding month 2020-07-01T00:00:00+00:00

如何在 C++ 中执行此操作? (其实我也需要当前时间戳到下个月时间戳的ceil,但是如果你给我提示如何实现地板功能,我想我可以自己写这个)

正如Alan Birtles在评论中指出的那样,这可以在 C++20 中轻松完成:

#include <chrono>

int
floor_to_month_utc(int timestamp)
{
    using namespace std::chrono;

    sys_seconds tp{seconds{timestamp}};
    year_month_day ymd = floor<days>(tp);
    sys_seconds result = sys_days{ymd.year()/ymd.month()/1};
    return result.time_since_epoch().count();
}

解释:

第一步是将输入放入<chrono>类型系统。 据了解, timestamp是自1970-01-01 00:00:00 UTC(不包括闰秒)以来的秒数。 这也称为Unix 时间

std::chrono::sys_seconds是对应于这些语义的 C++20 类型。 所以sys_seconds tp{seconds{timestamp}}; 首先将timestamp转换为持续时间seconds ,然后转换为time_point sys_seconds

下一个必须意识到这是一个日历计算,而不是一个时间计算。 使用的日历是民用日历,它是用 C++20 <chrono>建模的。 所以下一步就是将time_point tp转换为民用日历中的一天:

year_month_day ymd = floor<days>(tp);

floor<days>只是将精度截断为tpdays精度(使其成为自 1970-01-01 00:00:00 UTC 以来的天数)。

ymd是一个{year, month, day}数据结构,从days time_point转换而来,类型为std::chrono::year_month_day ymdfloor<days>(tp)都包含完全相同的信息。 但是信息存储在两种不同的数据结构中: {year, month, day} vs {count of days}

下一步是查找ymd所指的年份和月份的第一天。 这只是表达式ymd.year()/ymd.month()/1

这可以转换回{count of days}数据结构:

sys_days{ymd.year()/ymd.month()/1}

std::chrono::sys_days只是表达式floor<days>(tp)类型的类型别名,其类型为:

time_point<system_clock, days>

接下来, sys_days数据结构被隐式转换为seconds精度,并从该数据结构中提取并返回整数量。

C++20 <chrono>库的预览在这里,可以与 C++11/14/17 一起使用。 要将上述 function 移植到此预览库,只需添加"date/date.h"using namespace date; . "date/date.h"是一个只有头文件的库,所以不需要安装。

这可以像这样练习:

std::cout << floor_to_month_utc(1594386202) << '\n';

输出:

1593561600

将上面的代码与给出不同结果的答案进行比较是有益的:

1593626076

结果不同的原因可以追溯到日历计算和时间计算之间的区别。 日历计算是针对某些日历(民用、中国、儒略等)进行的。 而按时间顺序计算仅在固定(常规)时间单位上运行。 日历月份和年份没有固定的时间长度。

不过,C++20 <chrono>库可以执行按时间顺序计算的monthsyears 在处理持续数月或数年的物理或生物过程时,这有时是正确的答案。 这样的过程不关心人造日历。 所以在这种情况下,处理月和年的平均长度是有意义的。

这个说法:

floor<months>(sys_seconds{seconds{timestamp}})

简单地将自Unix 时间纪元以来的时间划分为常规的偶数月,每个月的长度恰好为 2,629,746 秒(民用月的平均长度)。 因此,如果您希望使用假设的统一月份进行时间顺序计算(如果您愿意,可以使用完全不同的日历),那么这个答案是正确的。

编辑:这是错误的按时间顺序计算。


正如评论中所建议的,使用 Howard Hinnant 的 `date.h` header, 以下似乎做我想要的 (使用 `int64_t` 来避免 2038 错误):
 #include"date.h" int64_t floor_to_month_utc(int64_t timestamp){ using namespace std::chrono; const auto dp = date::floor<date::months>(system_clock::time_point(seconds(timestamp))); return duration_cast<seconds>(dp.time_since_epoch()).count(); }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM