C++:floor unix 时间戳到 UTC 月
C++: floor unix timestamp to UTC month
假设我有一个 unix timetsamp
int timestamp=1594386202;
我想写一个函数
int floor_to_month_utc(int timestamp);
将时间戳记到相应月份的开始(UTC)。在此示例中,函数应满足 1593561600 == floor_to_month_utc(1594386202)
,因为 1594386202
对应于 2020-07-10T13:03:22+00:00
UTC 时间,而 1593561600
是相应月份 2020-07-01T00:00:00+00:00
.[=17= 的开始]
我如何在 C++ 中执行此操作? (实际上我还需要当前时间戳到下个月时间戳的ceil,但我认为如果你给我提示如何实现floor函数,我可以自己写这个)
编辑:
这是错误的时间顺序计算。
正如评论中所提议的那样,使用 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();
}
正如 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-0100:00:00UTC以来的秒数(不包括闰秒)。这也称为 Unix Time.
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>
只是将精度截断为 tp
到 days
精度(使其成为自 1970-01-01 00:00:00 UTC 以来的天数)。
ymd
是一个 {year, month, day}
数据结构,由 days
精度 time_point
转换而来,类型为 std::chrono::year_month_day
。 ymd
和 floor<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
精度,并从该数据结构中提取并返回整数。
A preview of the C++20 <chrono>
library is here 并且可以与 C++11/14/17 一起使用。要将上述功能移植到此预览库,只需添加 "date/date.h"
和 using namespace date;
。 "date/date.h"
是一个只有头文件的库,因此不需要安装。
可以这样练习:
std::cout << floor_to_month_utc(1594386202) << '\n';
输出:
1593561600
将上面的代码与给出不同结果的 进行比较是有指导意义的:
1593626076
结果不同的原因可以追溯到 calendrical 计算和 chronological 计算之间的区别。日历计算是根据某些日历(民用、中国、儒略等)完成的。而按时间顺序计算仅在固定(常规)时间单位上运行。日历月份和年份没有固定的时间长度。
C++20 <chrono>
库可以使用 months
和 years
执行时间顺序计算。在处理持续数月或数年的物理或生物过程时,这有时是正确的答案。这样的过程不关心人造日历。所以在这种情况下,处理平均月和年的长度是有意义的。
这条语句:
floor<months>(sys_seconds{seconds{timestamp}})
简单地将自Unix Time纪元以来的时间划分为规则的偶数月,每个月的长度恰好为2,629,746秒(民用月的平均长度)。因此,如果有人希望使用假设的统一月份(如果您愿意,则使用完全不同的日历)进行按时间顺序计算,则此答案是正确的。
假设我有一个 unix timetsamp
int timestamp=1594386202;
我想写一个函数
int floor_to_month_utc(int timestamp);
将时间戳记到相应月份的开始(UTC)。在此示例中,函数应满足 1593561600 == floor_to_month_utc(1594386202)
,因为 1594386202
对应于 2020-07-10T13:03:22+00:00
UTC 时间,而 1593561600
是相应月份 2020-07-01T00:00:00+00:00
.[=17= 的开始]
我如何在 C++ 中执行此操作? (实际上我还需要当前时间戳到下个月时间戳的ceil,但我认为如果你给我提示如何实现floor函数,我可以自己写这个)
编辑: 这是错误的时间顺序计算。
正如评论中所提议的那样,使用 Howard Hinnant 的 `date.h` header,
#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();
}
正如 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-0100:00:00UTC以来的秒数(不包括闰秒)。这也称为 Unix Time.
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>
只是将精度截断为 tp
到 days
精度(使其成为自 1970-01-01 00:00:00 UTC 以来的天数)。
ymd
是一个 {year, month, day}
数据结构,由 days
精度 time_point
转换而来,类型为 std::chrono::year_month_day
。 ymd
和 floor<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
精度,并从该数据结构中提取并返回整数。
A preview of the C++20 <chrono>
library is here 并且可以与 C++11/14/17 一起使用。要将上述功能移植到此预览库,只需添加 "date/date.h"
和 using namespace date;
。 "date/date.h"
是一个只有头文件的库,因此不需要安装。
可以这样练习:
std::cout << floor_to_month_utc(1594386202) << '\n';
输出:
1593561600
将上面的代码与给出不同结果的
1593626076
结果不同的原因可以追溯到 calendrical 计算和 chronological 计算之间的区别。日历计算是根据某些日历(民用、中国、儒略等)完成的。而按时间顺序计算仅在固定(常规)时间单位上运行。日历月份和年份没有固定的时间长度。
C++20 <chrono>
库可以使用 months
和 years
执行时间顺序计算。在处理持续数月或数年的物理或生物过程时,这有时是正确的答案。这样的过程不关心人造日历。所以在这种情况下,处理平均月和年的长度是有意义的。
这条语句:
floor<months>(sys_seconds{seconds{timestamp}})
简单地将自Unix Time纪元以来的时间划分为规则的偶数月,每个月的长度恰好为2,629,746秒(民用月的平均长度)。因此,如果有人希望使用假设的统一月份(如果您愿意,则使用完全不同的日历)进行按时间顺序计算,则此答案是正确的。