如何在C++11中打印当前系统时间(包括毫秒)?

10

我在获取带毫秒的实际系统时间方面遇到了问题。我找到的唯一一个好方法在Windows.h中,但我不能使用它。我应该使用std::chrono。我该如何做?

我花费了很多时间尝试通过谷歌搜索解决此问题,但我只找到了秒级精度的示例。

我正在尝试获取像这样的字符串:

[2014-11-25 22:15:38:449]

没有标准的方法可以打印带有毫秒的日期。使用 std::chrono,我认为你只能自己转换一个 time_point - TNA
您需要使用特定于平台的调用来获得毫秒级精度。 - Thomas Matthews
3
@ThomasMatthews 我非常确定,如果系统允许的话,chrono 可以达到几微秒的精度。例如,请尝试运行此代码:http://en.cppreference.com/w/cpp/chrono/time_point - Alex
4个回答

15

使用这个答案中的代码:

#include <chrono>
#include <ctime>
#include <iostream>

template <typename Duration>
void print_time(tm t, Duration fraction) {
    using namespace std::chrono;
    std::printf("[%04u-%02u-%02u %02u:%02u:%02u.%03u]\n", t.tm_year + 1900,
                t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
                static_cast<unsigned>(fraction / milliseconds(1)));

    // VS2013's library has a bug which may require you to replace
    // "fraction / milliseconds(1)" with
    // "duration_cast<milliseconds>(fraction).count()"
}

int main() {
    using namespace std;
    using namespace std::chrono;

    system_clock::time_point now = system_clock::now();
    system_clock::duration tp = now.time_since_epoch();

    tp -= duration_cast<seconds>(tp);

    time_t tt = system_clock::to_time_t(now);

    print_time(*gmtime(&tt), tp);
    print_time(*localtime(&tt), tp);
}

需要翻译的内容:

需要记住的一件事是,计时器返回亚毫秒值并不一定表示该计时器具有亚毫秒分辨率。我认为 Windows 在 VS2015 中的实现可能已经修复了,但他们一直在使用敏感于操作系统timeBeginPeriod()设置的计时器来支持他们的 chrono 实现,这会导致分辨率变化,而默认设置是 16 毫秒。

此外,上述代码假设既没有 UTC 也没有本地时区与std::chrono::system_clock的时代相差一个小数秒值。


使用 Howard 的日期函数避免 ctime 的示例:http://coliru.stacked-crooked.com/a/98db840b238d3ce7


你只需要从tp中减去秒数,因为它将持续时间转换为秒,无论它们有多长。只需使用 seconds s = duration_cast<seconds>(tp); tp -= s; 即可。 - Alex
没错,其他值只用于“调试”代码中显示完整的持续时间。 - bames53
3
如果您不想费力阅读C API,您可以像这样做:http://howardhinnant.github.io/date_algorithms.html#What%20can%20I%20do%20with%20that%20<code>chrono</code>%20compatibility? - Howard Hinnant
1
我正在尝试编写一个类似这样的解决方案,并看到了“如果std::time_t精度较低,则实现定义是否舍入或截断该值”。这意味着我们不知道是否可以仅添加毫秒,因为to_time_t()中的秒可能会高一次。我的理解正确吗? - Jay Miller
@JayMiller 是的,没错。我不确定大多数实现是怎么做的。你可能想直接使用Howard的日期函数来替换to_time_t() - bames53
显示剩余2条评论

4
这个答案仍然使用了一些C API,但只在函数中使用,所以你可以忽略它:
template<typename T>
void print_time(std::chrono::time_point<T> time) {
    using namespace std;
    using namespace std::chrono;

    time_t curr_time = T::to_time_t(time);
    char sRep[100];
    strftime(sRep,sizeof(sRep),"%Y-%m-%d %H:%M:%S",localtime(&curr_time));

    typename T::duration since_epoch = time.time_since_epoch();
    seconds s = duration_cast<seconds>(since_epoch);
    since_epoch -= s;
    milliseconds milli = duration_cast<milliseconds>(since_epoch);

    cout << '[' << sRep << ":" << milli.count() << "]\n";
}

这只是对bames53代码的重写,但使用strftime来缩短代码。


如果我没记错的话,在Windows上是没有strftime函数的。 - Everyone
由于strftime是C++标准库(在ctime中)的一部分,我怀疑它在Windows中是可用的。 - paxdiablo

0

有没有人注意到 to_time_t 函数将秒数四舍五入了,而不是截断

auto now = system_clock::now();
time_t secs = system_clock::to_time_t(now);
now {_MyDur={_MyRep=15107091978759765 } }
secs = 1510709198

所以当你加上毫秒时

auto tse = now.time_since_epoch();
auto now_ms = duration_cast<milliseconds>(tse);
auto now_s = duration_cast<seconds>(tse);
auto jst_ms = now_ms - now_s;
DWORD msecs = jst_ms.count();
msecs = 875

secs 应该是 1510709197,但看看现在的 now_s,它是正确的

now_s {_MyRep=1510709197 }  

0

std::chrono 提供了表示时间点或两个时间点之间经过的持续时间的实用工具。它允许您获取有关这些时间间隔的信息。

它不提供任何日历信息。不幸的是,目前在C++标准中没有这方面的工具。boost::date_time 可能会对此有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接