Unix时间戳被定义为自1970年1月1日UTC以来的秒数,但不计算所有的秒数。这有点荒谬,人们不禁要想一下它的意义所在,因此我认为这是一个愚蠢的问题。
无论如何,让我们看一下一些平台关于time_t
和time()
的文档。
Linux:
time()返回自1970-01-01 00:00:00 +0000 (UTC)时刻以来的秒数。
POSIX.1使用一个公式近似计算从指定时间到时代之间的秒数,该公式考虑了所有能被4整除的年份都是闰年,但如果它们也能被100整除,则不是闰年,除非它们也能被400整除,在这种情况下,它们是闰年。由于跳秒和系统时钟不需要与标准参考同步,因此该值与实际时间和时代之间的秒数不同。意图是使自时代以来的秒值的解释保持一致;详见POSIX.1-2008理由A.4.15。
Windows:
time函数返回自协调世界时(UTC)1970年1月1日午夜(00:00:00)以来经过的秒数,根据系统时钟。
Mac OS X:
ctime()、gmtime()和localtime()函数都使用以自1970年1月1日UTC以来的秒数表示日期和时间的参数。
asctime()、ctime()、difftime()、gmtime()、localtime()和mktime()函数符合ISO/IEC 9899:1990(即ISO C90)规范,并符合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所建议的,您可以做一些愚蠢的事情,比如:
std::tm c = { 0, 0, 0, 1, 0, 70, 0, 0, -1};
std::time_t l = std::mktime(&c);
std::tm m = *std::gmtime(&l);
std::time_t n = std::mktime(&m);
l -= (n-l);
l
现在应该表示自1970年1月1日UTC以来(错误的)秒数。只要系统时区的系统纪元和1970年1月1日之间没有闰秒,或者与系统纪元相同量的时间内没有闰秒,那么任何计算出的闰秒都应该被抵消,l
就会像Unix时间戳一样错误。
另一个选择是使用一个不错的日期库,比如Howard Hinnant's chrono::date
。(Howard Hinnant 是 C++11 的 <chrono>
库的开发人员之一。)
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);
如果您想处理闰秒,Howard Hinnant还提供了一个库,其中包括处理闰秒的设施以及解析时区数据库作为闰秒数据源的功能。
std::time_t t = std::chrono::system_clock::to_time_t(tp);
(其中tp
是time_point
类型) - Andy Prowltime_t
也不能保证是基于Unix纪元的。 - Mike Seymourmktime
函数以本地时间作为输入,而不是UTC时间。我认为没有任何方法可以使用标准库将UTC日期/时间转换为time_t
。 - Mike Seymourgmttime()
呢?它似乎可以与UTC时间一起使用。 - Andy Prowlmktime()
将编码在tm
结构中的所需日期转换为本地时间time_t
值,然后使用gmtime()
将该值转换为UTCtm
结构,然后找出哪个tm
结构在作为输入提供给mktime()
时生成所需的UTCtime_t
值... - Andy Prowl