提问者:小点点

C++:楼层unix时间戳到UTC月


假设我有一个unix时间采样

int timestamp=1594386202;

我想写一个函数

int floor_to_month_utc(int timestamp);

将时间戳设置到相应月份的开始(以UTC表示)。 在本例中,函数应满足1593561600==floor_to_month_utc(1594386202),因为1594386202对应于2020-07-10t13:03:22+00:00UTC时间,且1593561600是相应月份2020-07-01t00:00:00+00:00的开始。

我如何在C++中做到这一点? (实际上我也需要当前时间戳到下个月时间戳的上限,但我想如果你给我一个如何实现地板函数的提示,我可以自己写这个)


共2个答案

匿名用户

正如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();
}

解释:

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

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

下一个必须认识到这是一个历法计算,而不是一个时间计算。 使用的日历是民用日历,它是用C++20建模的。 因此下一步是将time_pointtP转换为民用日历中的某一天:

year_month_day ymd = floor<days>(tp);

floor简单地将精度截断为tPdays精度(使其成为自1970-01-01 00:00:00 UTC以来的天数)。

YMD是一种{年,月,日}数据结构,由-precisiontime_point转换而来,类型为std::chrono::year_month_dayymdfloor(tp包含完全相同的信息。 但是信息存储在两种不同的数据结构中:{year,month,day}{count of days}

下一步是查找ymd引用的年和月的第一天。 这就是表达式ymd.year()/ymd.month()/1

这可以通过以下方式转换回{天数计数}数据结构:

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

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

time_point<system_clock, days>

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

这里是C++20库的预览,可以与C++11/14/17一起使用。 要将上述函数移植到这个预览库,只需添加“date/date.h”使用名称空间date;即可。 “date/date.h”是一个只有头的库,因此不需要安装。

这可以像这样进行:

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

输出:

1593561600

将上面的代码与给出不同结果的这个答案进行比较是有启发意义的:

1593626076

结果不同的原因要追溯到历法计算和年代计算之间的区别。 历法计算是相对于某些日历(民事,中国,朱利安,无论什么)进行的。 而按时间顺序计算只在固定的(规则的)时间单位上操作。 历法上的月和年没有固定的时间长度。

不过,C++20库可以使用执行时间计算。 在处理长达数月或数年的物理或生物过程时,这有时是正确的答案。 这样的过程并不关心人工制作的日历。 所以在这种情况下,处理月和年的平均长度是有意义的。

这一声明:

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

简单地将Unix时间纪元以来的时间划分为规则的,偶数的月份,每个月份的长度正好为2,629,746秒(民用月份的平均长度)。 因此,如果你想用假设的统一月份(如果你愿意的话,一个完全不同的日历)按时间顺序计算的话,这个答案是正确的。

匿名用户

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

#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();
}

相关问题


MySQL Query : SELECT * FROM v9_ask_question WHERE 1=1 AND question regexp '(c++|楼层|unix|时间|戳|utc)' ORDER BY qid DESC LIMIT 20
MySQL Error : Got error 'repetition-operator operand invalid' from regexp
MySQL Errno : 1139
Message : Got error 'repetition-operator operand invalid' from regexp
Need Help?