unix 时间戳定义为自 1970 年 1 月 1 日 UTC 以来的秒数,但不计算所有秒数。这有点荒谬,人们不得不想知道它的意义何在,所以我同意这是一个愚蠢的问题。
无论如何,让我们看一下 和 的一些平台time_t
文档time()
。
Linux:
time() 以自 Epoch 1970-01-01 00:00:00 +0000 (UTC) 以来的秒数返回时间。
POSIX.1 使用一个公式定义自 Epoch 以来的秒数,该公式近似于指定时间和 Epoch 之间的秒数。这个公式考虑了所有能被 4 整除的年份都是闰年,但能被 100 整除的年份不是闰年,除非它们也能被 400 整除,在这种情况下它们就是闰年。该值与时间和纪元之间的实际秒数不同,因为闰秒和系统时钟不需要与标准参考同步。目的是自 Epoch 值以来对秒数的解释是一致的;请参阅 POSIX.1-2008 基本原理 A.4.15 了解更多基本原理。
窗户:
time 函数根据系统时钟返回自 1970 年 1 月 1 日午夜 (00:00:00) 以来经过的秒数,协调世界时 (UTC)。
Mac OS X:
函数 ctime()、gmtime() 和 localtime() 都将一个时间值作为参数,该时间值表示自 Epoch(UTC 时间 00:00:00,1970 年 1 月 1 日)以来的时间(以秒为单位);
如果ISO C90''), and conform to
ISO/IEC 9945-1:1996 (
所选本地时区不包含闰秒表(参见 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时间戳错误的方式一样。
另一种选择是使用不错的日期库,例如Howard Hinnant 的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 还提供了一个库,其中包括处理闰秒以及解析时区数据库作为闰秒数据源的工具。