如何打印C++11的time_point?

88

我已经创建了一个时间点,但是我一直在努力将其打印到终端上。

#include <iostream>
#include <chrono>

int main(){

    //set time_point to current time
    std::chrono::time_point<std::chrono::system_clock,std::chrono::nanoseconds> time_point;
    time_point = std::chrono::system_clock::now();

    //print the time
    //...

    return 0;
}
我能找到的唯一打印一个time_point的文档在这里:http://en.cppreference.com/w/cpp/chrono/time_point。然而,我甚至无法像示例那样基于我的time_point创建一个time_t。
std::time_t now_c = std::chrono::system_clock::to_time_t(time_point); //does not compile

错误:

/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/chrono: In instantiation of ‘constexpr std::chrono::time_point<_Clock, _Dur>::time_point(const std::chrono::time_point<_Clock, _Dur2>&) [with _Dur2 = std::chrono::duration<long int, std::ratio<1l, 1000000000l> >; _Clock = std::chrono::system_clock; _Dur = std::chrono::duration<long int, std::ratio<1l, 1000000l> >]’:
time.cpp:13:69:   required from here
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/chrono:540:32: error: no matching function for call to ‘std::chrono::duration<long int, std::ratio<1l, 1000000l> >::duration(std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<long int, std::ratio<1l, 1000000000l> > >::duration)’
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/chrono:540:32: note: candidates are:
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/chrono:247:14: note: template<class _Rep2, class _Period2, class> constexpr std::chrono::duration::duration(const std::chrono::duration<_Rep2, _Period2>&)
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/chrono:247:14: note:   template argument deduction/substitution failed:
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/chrono:243:46: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/chrono:240:23: note: template<class _Rep2, class> constexpr std::chrono::duration::duration(const _Rep2&)
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/chrono:240:23: note:   template argument deduction/substitution failed:
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/chrono:236:27: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/chrono:234:12: note: constexpr std::chrono::duration<_Rep, _Period>::duration(const std::chrono::duration<_Rep, _Period>&) [with _Rep = long int; _Period = std::ratio<1l, 1000000l>]
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/chrono:234:12: note:   no known conversion for argument 1 from ‘std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<long int, std::ratio<1l, 1000000000l> > >::duration {aka std::chrono::duration<long int, std::ratio<1l, 1000000000l> >} to ‘const std::chrono::duration<long int, std::ratio<1l, 1000000l> >&’
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/chrono:232:12: note: constexpr std::chrono::duration<_Rep, _Period>::duration() [with _Rep = long int; _Period = std::ratio<1l, 1000000l>]
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/chrono:232:12: note:   candidate expects 0 arguments, 1 provided

5
我认为libstdc++(也就是GCC的STL实现)现在还不支持std::put_time,因此cppreference中的例子无法编译。请参阅http://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html。 - Cassio Neri
顺便说一下,如果你点击“运行此代码”,然后将编译器更改为clang 3.4(C++11),cppreference上的示例就可以编译。 - Cubbi
9个回答

60
在这篇文章中,为了清晰起见,我将省略std::chrono::限定符。我相信你知道它们应该放在哪里。

你的代码示例无法编译的原因是system_clock::now()的返回类型与你尝试赋值的变量类型(time_point<system_clock, nanoseconds>)不匹配。

system_clock::now()的文档返回值是system_clock::time_point,它是time_point<system_clock, system_clock::duration>的typedef。 system_clock::duration是实现定义的,通常使用microsecondsnanoseconds。看起来你的实现使用了microseconds,所以system_clock::now()的返回类型是time_point<system_clock, microseconds>

具有不同持续时间的time_point之间不能隐式转换,因此你会得到一个编译器错误。

你可以使用time_point_cast显式地将具有不同持续时间的时间点进行转换,因此以下内容将在你的系统上编译:

time_point<system_clock, nanoseconds> time_point;
time_point = time_point_cast<nanoseconds>(system_clock::now());
注意,time_point_cast 的显式模板参数是目标duration类型,而不是目标 time_point 类型。在 time_point_cast 中,时钟类型必须匹配,因此指定整个 time_point 类型(该类型在时钟类型和持续时间类型上进行模板化)将是冗余的。
当然,在您的情况下,由于您只想打印时间点,所以没有必要将其设置为任何特定的分辨率,因此您可以将time_point声明为与 system_clock::now() 返回的相同类型。一种简单的方法是使用system_clock::time_point typedef:
system_clock::time_point time_point;
time_point = system_clock::now();  // no time_point_cast needed

由于这是C++11,因此您还可以直接使用auto

auto time_point = system_clock::now(); 

解决了这个编译器错误后,转换为time_t就可以正常工作:

std::time_t now_c = std::chrono::system_clock::to_time_t(time_point);

现在您可以使用标准方法显示 time_t 值,例如 std::ctimestd::strftime。(正如 Cassio Neri 在您的问题的评论中指出的那样,更符合C++风格的 std::put_time 函数目前尚未受到GCC的支持)。


2
+1 更详细的解释和提到了 auto(实际上,这是C++,没有人会在下一行声明变量并赋值,即使没有 auto)。 - Christian Rau
6
如果不同长度的time_point共享相同的“Clock”并且右侧的“Duration”可以隐式转换为左侧的“Duration”,则它们可以相互隐式转换。在这个例子中,如果“system_clock::duration”是微秒或纳秒,则根据[time.point.cons]/p3,它会隐式转换为“time_point<system_clock,纳秒>”。 - Howard Hinnant
我花了一秒钟才意识到std::chrono::system_clock::time_pointstd::chrono::time_point<std::chrono::system_clock>是相同的。 - simplename

28

这是一道旧问题的更新回答:

对于一个std::chrono::time_point<std::chrono::system_clock, some-duration>,现在有第三方库可以给你更好的控制。对于基于其他时钟(clock)的时间点(time_points),目前仍然没有比获取内部表示然后打印输出更好的解决方案。

但是对于system_clock,使用这个库非常简单:

#include "date.h"
#include <iostream>

int
main()
{
    using namespace date;
    using namespace std::chrono;
    std::cout << system_clock::now() << " UTC\n";
}

只是为我输出了以下内容:

2016-07-19 03:21:01.910626 UTC

这是当前的UTC日期和微秒精度的时间。如果你的平台上system_clock::time_point具有纳秒精度,它将为您打印出纳秒精度。

2021更新

这是上述程序的C++20版本:

#include <chrono>
#include <iostream>

int
main()
{
    std::cout << std::chrono::system_clock::now() << " UTC\n";
}

10
嗯,我认为这应该是标准规定中的一部分。 - Abhinav Gauniyal
11
@AbhinavGauniyal: 正在处理中 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0355r1.html)。这很可能需要**你们**的大声帮助。委员会上有重要力量不喜欢这个提案,如果公众不发出强烈声音,他们将获胜。 - Howard Hinnant
2
竞争性提案采用替代(在我看来较差)的设计。请查看我的第三版提案,大约一周后会出现在http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/。 - Howard Hinnant
2
现在,“稍微修改的”date.h已经进入了C++ 2a,time_point输出是否包含在其中?我正在使用最新的gcc和-std=c++2a,但没有得到它。 - haelix
现在这个程序可以在MSVC 19上编译和运行了:https://gcc.godbolt.org/z/5TfvYszME - Howard Hinnant
显示剩余4条评论

19

这段代码可能会对你有所帮助:

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

template<typename Clock, typename Duration>
std::ostream &operator<<(std::ostream &stream,
  const std::chrono::time_point<Clock, Duration> &time_point) {
  const time_t time = Clock::to_time_t(time_point);
#if __GNUC__ > 4 || \
    ((__GNUC__ == 4) && __GNUC_MINOR__ > 8 && __GNUC_REVISION__ > 1)
  // Maybe the put_time will be implemented later?
  struct tm tm;
  localtime_r(&time, &tm);
  return stream << std::put_time(&tm, "%c"); // Print standard date&time
#else
  char buffer[26];
  ctime_r(&time, buffer);
  buffer[24] = '\0';  // Removes the newline that is added
  return stream << buffer;
#endif
}

int main() {
  std::cout << std::chrono::system_clock::now() << std::endl;
  // Wed May 22 14:17:03 2013
}

只有std::chrono::system_clock支持to_time_t,所以我认为将其作为模板没有意义。相反,可以直接将time_point作为const system_clock::time_point &time_point传递。 - David L.
1
取决于用户是否创建了一个带有 to_time_t 的自定义时钟。 - Matt Clarkson

13

从文档中看,纳秒似乎是问题的一部分,经过一番调查研究,我成功解决了这个问题:

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


int main(){

    //set time_point to current time
    std::chrono::time_point<std::chrono::system_clock> time_point;
    time_point = std::chrono::system_clock::now();

    std::time_t ttp = std::chrono::system_clock::to_time_t(time_point);
    std::cout << "time: " << std::ctime(&ttp);

    return 0;
}

尽管看起来std::chrono::microseconds可以正常工作:

std::chrono::time_point<std::chrono::system_clock,std::chrono::microseconds> time_point;

1
顺便说一句,一个更简洁的 auto time_point = std::chrono::system_clock::now(); 也可能会做到同样的效果。 - Christian Rau
2
@ChristianRau 当然,说得好。我通常喜欢尽可能保持代码与原始发布的代码接近,除非它明显有问题或错误。 - Shafik Yaghmour
1
还有一个更加简洁的方式:high_resolution_clock::now() - zwcloud

5

对于任何使用 time_point<steady_clock>(而不是 time_point<system_clock>)的人:

#include <chrono>
#include <iostream>

template<std::intmax_t resolution>
std::ostream &operator<<(
    std::ostream &stream,
    const std::chrono::duration<
        std::intmax_t,
        std::ratio<std::intmax_t(1), resolution>
    > &duration)
{
    const std::intmax_t ticks = duration.count();
    stream << (ticks / resolution) << '.';
    std::intmax_t div = resolution;
    std::intmax_t frac = ticks;
    for (;;) {
        frac %= div;
        if (frac == 0) break;
        div /= 10;
        stream << frac / div;
    }
    return stream;
}

template<typename Clock, typename Duration>
std::ostream &operator<<(
    std::ostream &stream,
    const std::chrono::time_point<Clock, Duration> &timepoint)
{
    Duration ago = timepoint.time_since_epoch();
    return stream << ago;
}

int main(){
    // print time_point
    std::chrono::time_point<std::chrono::steady_clock> now =
        std::chrono::steady_clock::now();
    std::cout << now << "\n";

    // print duration (such as the difference between 2 time_points)
    std::chrono::steady_clock::duration age = now - now;
    std::cout << age << "\n";
}

十进制数格式化程序并不是最高效的,但它不需要事先知道小数位数,如果你想使 resolution 可以被模板化,而你又无法为 ceil(log10(resolution)) 想出一个常量表达式。


1
为了获得额外的速度,您可以使用我的 itoa(它确实具有用于 ceil(log10(resolution)) 的常量表达式,但仅用于静态断言传递的缓冲区足够大;)... https://github.com/CarloWood/ai-utils/blob/master/itoa.h#L46 - Carlo Wood

1

ctime()在Visual C++中不起作用。我使用MS Visual Studio 2013。根据MSVC编译器的提示,我将上面的代码更改为使用ctime_s(...)。它奏效了。

//set time_point to current time
std::chrono::time_point<std::chrono::system_clock> time_point;
time_point = std::chrono::system_clock::now();

std::time_t ttp = std::chrono::system_clock::to_time_t(time_point);
char chr[50];
errno_t e = ctime_s(chr, 50, &ttp);
if (e) std::cout << "Error." << std::endl;
else std::cout << chr << std::endl;

1
#include<iostream>
#include<string>
#include<chrono>
#include<thread>
#include<ctime>

using namespace std;

string getTimeAsStr(chrono::system_clock::time_point& t)
{
    std::time_t time = std::chrono::system_clock::to_time_t(t);
    std::string time_str = std::ctime(&time);
    time_str.pop_back();
    return time_str;
}
ostream& operator<<(ostream& os, chrono::system_clock::time_point& t)
{
    os<<getTimeAsStr(t);
    return os;
}
int main()
{
    chrono::system_clock::time_point currentTime = chrono::system_clock::now();
    cout << currentTime<<endl;

    return 0;
}

1

又是一段代码片段。 好处是它相当独立,并支持微秒文本表示。

std::ostream& operator<<(std::ostream& stream, const std::chrono::system_clock::time_point& point)
{
    auto time = std::chrono::system_clock::to_time_t(point);
    std::tm* tm = std::localtime(&time);
    char buffer[26];
    std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S.", tm);
    stream << buffer;
    auto duration = point.time_since_epoch();
    auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration);
    auto remaining = std::chrono::duration_cast<std::chrono::nanoseconds>(duration - seconds);
    // remove microsecond cast line if you would like a higher resolution sub second time representation, then just stream remaining.count()
    auto micro = std::chrono::duration_cast<std::chrono::microseconds>(remaining);
    return stream << micro.count();
}

0

简而言之:如何打印出原始的std::chrono::time_point

#include <iostream>
#include <chrono>

int main()
{
  // begin is a std::chrono::time_point type
  // You can also use ::system_clock::now() to get the time since
  // Jan 1 1970 (differences between these linked below)
  auto begin = std::chrono::steady_clock::now();

  // print as nanoseconds. Can also choose ::microseconds, ::seconds, ::minutes,
  // ::hours. The type returned from .time_since_epoch() is
  // std::chrono::duration
  std::cout << "begin: " << std::chrono::duration_cast<std::chrono::nanoseconds>(begin.time_since_epoch()).count();

  return 0;
}

好家伙,我以为只需要30秒的谷歌搜索结果,结果却陷入了一个深不见底的研究项目。我只是想在我的程序中打印一些原始时间点,以便进行可视化比较,并不关心漂亮的打印效果。我相信其他答案也能起作用,但它们包含了大量的代码、使用ctime结构体、第三方库等等。我只是想找到一个最简单的解决方案,即“按原样打印这个值”,但并没有找到太多直接的方法。似乎不能简单地打印一个::time_point:
auto begin = std::chrono::steady_clock::now();
// BAD CODE, none of these work, in C++17 anyway
std::cout << begin;
std::cout << std::chrono::time_point_cast<std::chrono::nanoseconds>(begin);
std::cout << std::chrono::duration_cast<std::chrono::nanoseconds>(begin).count();
std::cout << std::chrono::duration_cast<std::chrono::nanoseconds>(begin - 0).count();

相反,似乎你只能打印一个 duration,所以在顶部所示的是从 这里 获取的一种快速创建时间段的方法,从 now 到纪元开始,这取决于您使用的时钟(基本上,::system_clock 是壁挂钟时间,而 ::steady_clock 是从某个点开始的单调时钟,例如系统上电)。对于我的目的,::steady_clock 肯定是更好的选择,但只要我是在比较同类产品,应该不会有太大问题。我只是在寻找一些视觉反馈,而不是非常准确的东西。
我在这里创建了一个草稿本demonstration,展示了我感兴趣的时间点如何打印以及::steady_clock::system_clock之间的一些区别。

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