如何获取自C++纪元 (MSVS) 以来的本地当前时间(以秒为单位)

How to get the local current time in seconds since epoch in C++ (MSVS)?

本文关键字:时间 为单位 MSVS 获取 何获取 C++ 纪元      更新时间:2023-10-16

我需要自纪元以来的本地(带时区偏移量(当前时间(以秒为单位(。下面的代码看起来有点笨拙,因为它创建了一个多余的中间临时结构 tm。为什么我必须获取time_t然后将其转换为 tm 才能返回time_t?有没有更好的方法?

time_t ct = time(0);
tm lct = tm();
localtime_s(&lct, &ct);
ct = _mkgmtime(&lct);

如果您想在可移植 C 中获取本地时间(应用时区和 DST(,那么是的,这通常是一个两步过程:从您的时代开始,首先调用localtime,然后对生成的细分struct tm执行一些操作。 (通常我接下来要做的是打电话给strftime

还可以调用 ctime 直接获取本地时间字符串。

涉及许多不同的函数调用的原因是,不幸的是,有几种不同的时间格式在使用中。 (原因是日期和时间很复杂! 您可以将时间表示为自 1970 年以来的秒。 您可以将其表示为struct tm。 您可以将其表示为字符串(采用几种亿万种格式之一(。 在Unix和Linux中,您可以将其表示为struct timevalstruct timespec

但是,正如您所发现的,有一件事没有一种简单或标准的方法可以做到,那就是将本地时间作为自 1970 年以来的秒数。 但原因是它不是一个非常有用的表示。 通常,您可能希望对日期/时间值执行两件事:(1( 对其执行计算或 (2( 向用户显示它。 如果要向用户显示它,则可能希望以本地时间显示它,因此有很多方法可以以所需的任何格式转换为人类可读格式的本地时间。 (正如我所说,通常的方法是打电话给localtime,然后strftime。 但是如果你想执行计算,实际上唯一的方法是在UTC中使用自1970年以来的秒,因为这会使所有其他棘手的问题消失。 一个月有多少天? 是闰年吗? 我们在哪个时区? 夏令时是否有效?

但是,如果您尝试将当地时间表示为自 1970 年以来的秒数,您可能会在撒谎。 例如,现在,时间是1460383736,即 14:08:56 UTC。 我坐的地方是10:08:56 EDT(美国东部时间,实际上是DST(。 所以我想我可以说这是自当地时间1970年以来的1460369336秒。 但是,再说一遍,1460369336秒前不是1970年1月1日的午夜,实际上是1969年12月31日的晚上11点。 它相差了一个小时,原因是 DST 在 1970 年 1 月 1 日未生效。

所以,最重要的是,我鼓励你重新思考你处理本地时间的方式,因为虽然可以计算这个"自 1970 年以来的秒数作为本地时间"值,但这是一件奇怪的事情,它可能会导致你遇到各种问题,这些问题比你使用更直接的方案更难解决。


但是,如果您真的愿意,您可以通过以下两种方法确定 UTC 和本地时间之间的偏移量,而无需调用 gmtime_mkgmtime

  1. 调用localtime,并查看tm_gmtoff字段。 (遗憾的是,此字段是非标准的,并非在所有系统上都存在。
  2. 调用过时的ftime函数,查看struct timebtimezone字段。 (这里有几个陷阱:不仅ftime过时和非标准,而且timezone场以分钟为单位,格林威治以西的区域是积极的,而tm_gmtoff是负面的。

但是,无论如何,这些或多或少会直接为您提供自 1970 年以来的 UTC 秒值中添加或减去的数字,以获得自 1970 年以来的"本地"秒数。

这是一种使用 C++11/14 <chrono> 库和这个免费的开源时区库进行此计算的方法,用于转换为本地时间。

#include "tz.h"
#include <iostream>
int
main()
{
    using namespace date;
    using namespace std;
    using namespace std::chrono;
    auto now = floor<seconds>(system_clock::now());
    auto s = current_zone()->to_local(now) - local_days{1970_y/jan/1};
    cout << s.count() << 'n';
}

首先通过 current_zone() 发现您当前的 IANA 时区。 然后你用system_clock::now()获取当前时间,并将其截断为seconds。 接下来,您可以将其转换为本地时间,然后从所需的任何纪元中减去结果(在本例中为 1970-01-01(。

结果的类型为 std::chrono::seconds

话虽如此,我对这样做持同样的保留意见,正如史蒂夫峰会的回答中所描述的那样。

如果您决定将时间戳表示为字符串,这也很容易完成:

auto now = make_zoned(current_zone(), floor<seconds>(system_clock::now()));
auto str = format("%F %T %z", now);

str有类型 std::string . 这只是为我输出:

2016-04-11 11:42:50 -0400
这是我当前的本地

时间(截断为秒(,以及我当前的本地 UTC 偏移量。

如果将来您认为秒精度太粗,则只需更改一行即可轻松地将上述代码更改为任何其他精度:

floor<milliseconds>(system_clock::now());

现在str的内容如下所示:

2016-04-11 11:42:50.368 -0400