将std :: chrono :: time_point转换为unix时间戳

问题描述 投票:27回答:4

如何在固定日期之后获得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)相同。

c++ c++11 unix-timestamp chrono
4个回答
32
投票

unix时间戳定义为1970年1月1日UTC以来的秒数,但不计算所有秒数。这有点荒谬,我不得不怀疑它的意义,所以我同意这是一个愚蠢的问题。

无论如何,让我们看看time_ttime()的一些平台文档。

Linux

time()返回自Epoch,1970-01-01 00:00:00 +0000(UTC)以来的秒数。

POSIX.1使用近似于指定时间和纪元之间的秒数的公式定义自纪元以来的秒数。这个公式考虑了这样的事实:所有可被4整除的年份都是闰年,但是可以被100整除的年份不是闰年,除非它们也可以被400整除,在这种情况下它们是闰年。由于闰秒并且系统时钟不需要与标准参考同步,因此该值与时间和Epoch之间的实际秒数不同。目的是自大纪元价值观以来对秒的解释是一致的;有关进一步的理由,请参阅POSIX.1-2008理由A.4.15。

Windows

time函数根据系统时钟返回自1970年1月1日午夜(00:00:00),协调世界时(UTC)以来经过的秒数。

Mac OS X

函数ctime(),gmtime()和localtime()都将一个时间值作为参数,该时间值表示自Epoch(1970年1月1日00:00:00 UTC)以来的秒数。

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日(系统时区)之间没有闰秒,或者在系统时代的另一个方向上的相同时间内,那么任何计算的闰秒都应该抵消,并且l将是unix时间戳错误的方式是错误的。


另一种选择是使用像Qazxswpoi这样的体面日期库。 (Howard Hinnant是参与C ++ 11 Howard Hinnant's chrono::date库的人之一。)

<chrono>

如果你想处理闰秒霍华德Hinnant还提供auto now = system_clock::now(); sys_days today = time_point_cast<days>(now); system_clock::time_point this_morning = today; sys_days unix_epoch = day(1)/jan/1970; days days_since_epoch = today - unix_epoch; auto s = now - this_morning; auto tz_offset = hours(0); int unix_timestamp = (days_since_epoch + s + tz_offset) / seconds(1); ,其中包括处理它们的设施以及解析时区数据库作为闰秒数据的来源。


7
投票

简而言之,这是我用来获取Unix时间戳的函数(自UTC时间1970年1月1日起的秒数):

a library

此功能的优点是默认参数值只为您提供当前时间。但是,如果您想将某个特定时间转换为unix时间戳,那么也可以将其转换为unix时间戳。


4
投票

那个C ++ 11实现怎么样?

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

2
投票

您可以使用auto microsecondsUTC = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); mktime()结构中编码的所需日期转换为本地时间tm值。

如果你需要UTC时间,那么使用time_tgmttime()值转换为UTC time_t结构,并从输出中得出,当输入tm时,你得到哪个tm结构产生所需的UTC time_t

有点精心,但希望它能起作用或者至少提供一个提示。

© www.soinside.com 2019 - 2024. All rights reserved.