自固定日期起如何获得std::chrono::duration
?我需要这个来将std::chrono::time_point
转换为unix时间戳。
将代码插入XXX
auto unix_epoch_start = XXX;
auto time = std::chrono::system_clock::now();
auto delta = time - unix_epoc_start;
auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(delta).count();
我知道time_point
有一个方法time_since_epoch()
,但不保证这与unix纪元(1970年1月1日00:00:00 UTC)相同。
答案 0 :(得分:31)
unix时间戳记定义为1970年1月1日UTC以来的秒数,但不计算所有秒数。这有点荒谬,人们不禁要问这是什么意思,所以我同意这是一个愚蠢的问题。
无论如何,让我们看一下time_t
和time()
的一些平台文档。
time()将时间作为自纪元,1970-01-01 00:00:00 +0000(UTC)以来的秒数返回。
POSIX.1使用近似于指定时间和纪元之间的秒数的公式定义自纪元以来的秒数。这个公式考虑了这样的事实,即所有可被4整除的年份都是闰年,但是可以被100整除的年份不是闰年,除非它们也可以被400整除,在这种情况下它们是闰年。由于闰秒并且系统时钟不需要与标准参考同步,因此该值与时间和Epoch之间的实际秒数不同。目的是自大纪元价值观以来对秒的解释是一致的;有关进一步的理由,请参阅POSIX.1-2008理由A.4.15。
时间函数根据系统时钟返回自1970年1月1日午夜(00:00:00),协调世界时(UTC)以来经过的秒数。
函数ctime(),gmtime()和localtime()都作为参数 表示自Epoch(00:00:00)以来的秒数的时间值 UTC,1970年1月1日;
asctime(),ctime(),difftime(),gmtime(),localtime()和mktime() 函数符合ISO / IEC 9899:1990(
ISO C90''), and conform to ISO/IEC 9945-1:1996 (
POSIX.1'')提供选定的本地时区 不包含闰秒表(参见zic(8))。
可以在其他系统中找到类似的文档,例如AIX,HP-UX,Solaris等。
因此,尽管未在 C ++ 中指定,但有一种简单且可广泛移植的方式来获取Unix时间戳:
auto unix_timestamp = std::chrono::seconds(std::time(NULL));
如果您想要自1970年1月1日UTC以来的毫秒数(同样不包括所有这些),那么您可以这样做:
int unix_timestamp_x_1000 = std::chrono::milliseconds(unix_timestamp).count();
请记住,这些值不是实际值,因此通常不能在算术中使用unix时间戳。例如,减去unix时间戳并不能准确计算时间之间的秒数。或者,如果你做了类似的事情:
std::chrono::steady_clock::now() - unix_timestamp;
你不会得到实际对应于1970-01-01 00:00:00 + 0000的时间点。
Andy Prowl建议你可以做一些愚蠢的事情:
// 1 Jan 1970 (no time zone)
std::tm c = { 0, 0, 0, 1, 0, 70, 0, 0, -1};
// treat it as 1 Jan 1970 (your system's time zone) and get the
// number of seconds since your system's epoch (leap seconds may
// or may not be included)
std::time_t l = std::mktime(&c);
// get a calender time for that time_point in UTC. When interpreted
// as UTC this represents the same calendar date and time as the
// original, but if we change the timezone to the system TZ then it
// represents a time offset from the original calendar time by as
// much as UTC differs from the local timezone.
std::tm m = *std::gmtime(&l);
// Treat the new calendar time as offset time in the local TZ. Get
// the number of seconds since the system epoch (again, leap seconds
// may or may not be counted).
std::time_t n = std::mktime(&m);
l -= (n-l); // subtract the difference
l
现在应该代表1970年1月1日UTC以来的(错误)秒数。只要系统时期和1970年1月1日(系统时区)之间没有闰秒,或者在系统时期的另一个方向上的相同时间内,那么任何计算的闰秒都应该抵消并且{{1只是unix时间戳错误的方式会出错。
另一种选择是使用像Howard Hinnant's chrono::date
这样的体面日期库。 (Howard Hinnant是参与C ++ 11 l
库的人之一。)
<chrono>
如果你想处理闰秒,Howard Hinnant还提供a library,其中包括处理它们的工具以及解析时区数据库作为闰秒数据的来源。
答案 1 :(得分:7)
长话短说,这是我用来获取Unix时间戳的函数(自UTC时间1970年1月1日起的秒数):
static uint64_t getUnixTimeStamp(const std::time_t* t = nullptr)
{
//if specific time is not passed then get current time
std::time_t st = t == nullptr ? std::time(nullptr) : *t;
auto secs = static_cast<std::chrono::seconds>(st).count();
return static_cast<uint64_t>(secs);
}
此功能的优点是默认参数值只为您提供当前时间。但是,如果您想将某个特定时间转换为unix时间戳,那么也可以这样做。
答案 2 :(得分:2)
您可以使用mktime()
将tm
结构中编码的所需日期转换为本地时间 time_t
值。
如果您需要UTC时间,请使用gmttime()
将time_t
值转换为UTC tm
结构,然后从输出中找出tm
当在time_t
的输入中给出时,结构会产生所需的UTC mktime()
。
有点复杂,但希望它能起作用或者至少提供一个提示。
答案 3 :(得分:2)
此C ++ 11实现如何
auto microsecondsUTC = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
答案 4 :(得分:0)
我知道 time_point 有一个方法 time_since_epoch() 但它不是 保证这与unix时代相同(00:00:00 UTC on 1 1970 年 1 月)。
从 C++20 和 P0355R7 开始,当 std::chrono::time_point::time_since_epoch
是 std::chrono::time_point
时,可以保证 std::chrono::system_clock
是 UNIX 时代。