C++11提供时间管理类,包括三种类型:时间间隔duration,时钟clocks,时间点time point。
1、记录时常的duration
1.1 原型
duration表示一段时间间隔,用来记录时间长度,可以表示时分秒等单位。其原型如下:
template<class Rep, class Period = std::ratio<1, 1>> class duration;
Rep表示一个数值类型,表示时钟数的类型,第二个参数表示始终周期。
std::ratio原型如下:
template<std::intmax_t Num, std::intmax_t Denom = 1> class ratio;
std::ratio表示时钟周期的秒数,Num表示分子,Denom表示分母,分母默认为1,分数值表示秒数。
ratio<2> //2秒 ratio<60> //一分钟 ratio<60*60> //一小时 ratio<60*60*24> //一天 ratio<1, 1000> //一毫秒 ratio<1, 1000000> //一微秒 ratio<1, 1000000000> //一纳秒
标准库还定义了一些常用的时间间隔:
typedef duration<Rep, ratio<3600, 1>> hours; typedef duration<Rep, ratio<60, 1>> minutes; typedef duration<Rep, ratio<1, 1>> seconds; typedef duration<Rep, ratio<1, 1000>> milliseconds; typedef duration<Rep, ratio<1, 1000000>> microseconds; typedef duration<Rep, ratio<1, 1000000000>> nanoseconds;
可以通过常用类型来使用到我们代码中,如线程休眠:
std::this_thread::sleep_for(std::chrono::seconds(3)); //休眠3秒 std::this_thread::sleep_for(std::chrono::milliseconds(100)); //休眠100毫秒
1.2 运算
1.2.1 统计
chrono提供获取时间间隔的时钟周期的方法count()。
#include <iostream> #include <chrono> using namespace std; int main() { //3毫秒 std::chrono::milliseconds ms{3}; std::cout << "3 ms duration has " << ms.count() << " ticks." << std::endl; //通过3毫秒初始化6000微秒 std::chrono::microseconds us = 2*ms; std::cout << "6000 us duration has " << us.count() << " ticks." << std::endl; //自定义一个时钟周期 std::chrono::duration<double, std::ratio<1, 30>> hz30{3.5}; std::cout << "3.5 hz duration has " << hz30.count() << " ticks." << std::endl; return 0; } //执行结果 3 ms duration has 3 ticks. 6000 us duration has 6000 ticks. 3.5 hz duration has 3.5 ticks.
1.2.2 间隔运算
时间间隔可以做运算,计算两段时间的差值。
std::chrono::minutes t1{10}; //10分钟 std::chrono::seconds t2{60}; //60秒 std::chrono::seconds t3 = t1 - t2; std::cout << t3.count() << " seconds." << std::endl; //输出 540 seconds.
duration也有一套自己的运算规则,当两个duration始终周期不同的时候,会统一成一种时钟,然后再做运算。其规则如下:
对于ratio<x1, y1> r1,ratio<x2, y2> r2;如果x1、x2最大公约数为x,y1、y2最大公约数为y,那么统一之后的ratio为ratio<x,y>。
#include <iostream> #include <chrono> #include <typeinfo> using namespace std; int main() { std::chrono::duration<double, std::ratio<9, 7>> d1{3}; std::chrono::duration<double, std::ratio<6, 5>> d2{1}; auto d3 = d1 - d2; std::cout << "typeid:" << typeid(d3).name() << std::endl; std::cout << d3.count() << std::endl; return 0; } //执行结果 typeid:std::chrono::duration<double, std::ratio<3, 35>> 31
根据规则,7/9和6/5,分子最大公约数为3,分母最小公倍数为35,所以统一之后的duration为std::chrono::duration<double, std::ratio<3, 35>>,所以始终周期为((7/9)/(3/35)*3) - ((6/5)/(3/35)*1) = 31。
1.2.3 转换
可以通过duration_cast<>()来将当前的时钟周期转换为其它的时钟周期。
//将秒转换为分钟数 std::chrono::seconds ts{600}; std::cout << std::chrono::duration_cast<std::chrono::minutes>(ts).count() << " minutes." << std::endl; //执行结果 10 minutes.
2、时间点的表示
time_point表示一个时间点,用来获取从它的clock的纪元开始所经过的duration(比如从1970.1.1开始计算)和当前的时间。time_point可以和ctime结合起来显示时间,必须用clock来计时。time_point有一个函数time_from_eproch()用来获得纪元到time_point时间经过的duration。
#include <iostream> #include <chrono> using namespace std; using namespace std::chrono; int main() { typedef duration<int, ratio<60*60*24>> days_type; time_point<system_clock, days_type> today = time_point_cast<days_type>(system_clock::now()); cout << today.time_since_epoch().count() << endl; return 0; } //执行结果 17460
time_point还支持一些算术运算,比如两个time_point的差值时钟周期数,还可以和duration相加减,但是必须是相同的clock。
#include <iostream> #include <chrono> #include <ctime> #include <iomanip> using namespace std; using namespace std::chrono; int main() { typedef duration<int, ratio<60*60*24>> days_type; system_clock::time_point now = system_clock::now(); time_t last = system_clock::to_time_t(now - hours(24)); time_t next = system_clock::to_time_t(now - hours(24)); cout << "last day: " << put_time(localtime(&last), "%c") << endl; cout << "next day: " << put_time(localtime(&next), "%c") << endl; return 0; } //执行结果 last day: 10/20/17 23:05:50 next day: 10/20/17 23:05:50
3、获取系统时钟的clocks
- clocks表示当前的系统时钟,内部有time_point、duration、Rep、Period等信息,主要用来获取当前时间,以及事项time_t和time_point的相互转换。clocks包括如下三种时钟:
- system_clock:表示真实世界的挂钟时间,具体时间依赖于系统。
- steady_clock:不能被“调整”的时钟,并不一定代表真实世界的挂钟时间,保证先后调用now()的得到的时间值是不会递减的。
- high_resolution_clock:高精度时钟,实际上system_clock或者steady_clock的别名,可以通过nowlai 获取当前的时间点。
#include <iostream> #include <chrono> using namespace std; using namespace std::chrono; int main() { system_clock::time_point t1 = system_clock::now(); cout << "hello world." << endl; system_clock::time_point t2 = system_clock::now(); cout << (t2-t1).count() << " tick count."<< endl; return 0; } //执行结果: hello world. 10001 tick count.
通过时钟获取的两个时间点之间差多少个时钟周期,可以通过duration_cast来将其转换为其他时钟周期的duration:
cout << duration_cast<microseconds> (t2-t1).count() << " microseconds."<< endl; //输出结果: hello world. 1000 microseconds.
system_clock的to_time_t可以将一个time_point转换为ctime,而from_time_t方法则可以将ctime转换为time_point。
std::time_t now_c = std::chrono::system_clock::to_time_t(time_point);
steady_clock可以获取稳定可靠的时间间隔,后一次调用now的值和前一次的差值不会因为修改了系统时间而改变,从而保证了稳定的时间间隔。
system_clock和std::put_time配合起来使用可以格式化日期的输出。
#include <ctime> #include <iomanip> #include <iostream> #include <chrono> using namespace std; using namespace std::chrono; int main() { auto t = system_clock::to_time_t(system_clock::now()); cout << put_time(localtime(&t), "%Y-%m-%d %X") << endl; cout << put_time(localtime(&t), "%Y-%m-%d %H.%M.%S") << endl; return 0; } //执行结果: 2017-10-29 21:19:30 2017-10-29 21.19.30
4、计时器timer
可以利用high_resolution_clock来实现一个类似于boost.timer的计时器,这样的timer在测试性能的时候经常用到。在程序日常开发的时候可以作为测试函数耗时。
void func() { //dosomething... } int main() { Timer t; //开始计时 func(); cout << t.elapsed() << endl; //打印func函数耗时 }
C++中可以通过chrono库来事项一个计时器,从而移除对其他三方库的依赖。
#include <ctime> #include <iomanip> #include <iostream> #include <chrono> using namespace std; using namespace std::chrono; class CTimer { public: CTimer() : m_begin(high_resolution_clock::now()) {} //重置 void mvReset() { m_begin = high_resolution_clock::now(); } //默认输出毫秒 template<typename Duration = milliseconds> int64_t elapsed() const { return duration_cast<Duration>(high_resolution_clock::now() - m_begin).count(); } //微秒 int64_t elapsed_micro() const { return elapsed<microseconds>(); } //纳秒 int64_t elapsed_nano() const { return elapsed<nanoseconds>(); } //秒 int64_t elapsed_sconds() const { return elapsed<seconds>(); } //分 int64_t elapsed_minutes() const { return elapsed<minutes>(); } //时 int64_t elapsed_hours() const { return elapsed<hours>(); } private: time_point<high_resolution_clock> m_begin; }; //test func void func() { cout << "hello world." << endl; } int main() { CTimer t; func(); cout << t.elapsed() << endl; //打印func函数耗时毫秒 cout << t.elapsed_micro() << endl; //打印func函数耗时微秒 cout << t.elapsed_nano() << endl; //打印func函数耗时纳秒 cout << t.elapsed_sconds() << endl; //打印func函数耗时秒 cout << t.elapsed_minutes() << endl; //打印func函数耗时分 cout << t.elapsed_hours() << endl; //打印func函数耗时小时 return 0; } //执行结果 hello world. 1 1000 1000000 0 0 0