首頁 > 軟體

C++11中的chrono庫詳解

2023-03-19 06:03:33

前言

C++11提供了日期時間相關的庫chrono,通過chrono庫可以很方便的處理日期和時間。chrono庫主要包含3種型別:時間間隔duration、時鐘clocks和時間點time_point

1、記錄時長的duration

duration為一個模板類,表示時間間隔,可以是幾秒、幾分鐘或者幾個小時的時間間隔。duration的原型如下:

template <class Rep, 
class Period = ratio<1> >
class duration;

第一模板引數Rep是一個數值型別,表示時鐘數的型別;第二個模板引數是一個預設模板引數std::ratio,表示時鐘週期,它的原型如下:

template <intmax_t N, 
intmax_t D = 1
> class ratio;

它表示每個時鐘週期的秒數,其中第一個模板引數N代表分子,D代表分母,分母預設為1,因此,ratio代表的是一個分子除以分母的分數值。比如:

ratio<2>	//代表2秒
ratio<60>	//代表1分鐘
ratio<60*60>	//代表1小時
ratio<60*60*24>	//代表1天
ratio<1, 1000>	//代表1毫秒
ratio<1, 1000000>	//代表1微秒
ratio<1, 1000000000>	//代表1納秒

為了方便使用,標準庫定義了一些常用的時間間隔,如時、分、秒、毫秒、微秒和納秒,在chrono名稱空間下,定義如下(vs2013的原始碼):

typedef duration<long long, nano> nanoseconds;
typedef duration<long long, micro> microseconds;
typedef duration<long long, milli> milliseconds;
typedef duration<long long> seconds;
typedef duration<int, ratio<60> > minutes;
typedef duration<int, ratio<3600> > hours;

通過定義這些常用的時間間隔型別,我們能方便的使用它們,比如執行緒休眠:

//休眠100毫秒
this_thread::sleep_for(std::chrono::duration<int, ratio<1, 100>>(100));
this_thread::sleep_for(std::chrono::microseconds(100));//更簡單

//休眠3秒
this_thread::sleep_for(std::chrono::duration<int>(3));
this_thread::sleep_for(std::chrono::seconds(3));//更簡單

chrono還提供了獲取時間間隔的時鐘週期數的方法count(),它的基本用法如下:

#include<iostream>
#include<chrono>
int main()
{
	std::chrono::seconds s(3);//3秒
	std::chrono::milliseconds ms = 2 * s;//6000毫秒
	std::cout << "3 s duration has " << s.count() << " ticksn" << "6000 ms duration has " << ms.count() << " ticksn";
}

執行結果:

duration在某些情況下可以進行轉換,例如,當duration的Rep都為整型,且源Period要大於目標Period時或者目標duration的Rep為浮點數時可以使用傳統型別轉化或者隱式呼叫其單值建構函式,不必呼叫duration_cast

int main()
{
	//目標duration的Rep為double
	std::chrono::milliseconds int_milliseconds(1024);       // 1024ms
	std::chrono::microseconds int_microseconds(1024);       // 1024us
	std::chrono::duration<double> double_seconds;
	double_seconds = int_microseconds;	//1024ms = 1.024s
	double_seconds = int_milliseconds;	//1024us = 0.001024s


	//當duration的Rep都為整型,且源Period可被目標Period整除時
	int_microseconds = int_milliseconds; //ms賦值給us可以,但是us賦值給ms不可
	int_milliseconds = std::chrono::seconds(1);	//s賦值給ms可以,但是ms賦值給s不可以


	//源duration的Rep為double, 目標duration的Rep不為double,不能轉換
	//std::chrono::milliseconds t1 = std::chrono::duration<double>(1024);

/*
 * 資料會發生截斷時的轉化
 * chrono庫提供了duration之間相互轉化的函數,其定義如下
 *      template <class ToDuration, class Rep, class Period>
 *      constexpr ToDuration duration_cast(const duration<Rep,Period>& d);
*/
    std::chrono::seconds t1 = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::milliseconds(1024));               // 1s = 1024ms(精度損失)
    std::chrono::seconds t2 = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::duration<double>(1.024));          // 1s = 1.024s 
}

時間間隔之間可以做運算,計算兩端時間間隔的差值的範例如下:

int main()
{
	std::chrono::minutes t1(10);
	std::chrono::seconds t2(50);
	std::chrono::seconds t3 = t1 - t2;
	cout << t3.count() << " second" << endl;
}

執行結果:

其中,t1代表10分鐘,t2代表50秒,t3則是t1減t2,也就是600-50=550秒。通過呼叫t3的count()輸出差值550個時鐘週期,因為t3的時鐘週期為1秒,所以t3表示時間間隔為550秒。

值得注意的是,duration的加減運算有一定的規則,當兩個duration時鐘週期不相同的時候,會先統一成一種時鐘,然後再作加減運算。統一成一種時鐘的規則如下:

對於ratio<x1, y1>count1和ratio<x2, y2>count2。如果x1、x2的最大公約數為x,y1、y2的最小公倍數為y,那麼統一之後的ratio為ratio<x, y>

例如:

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;
	cout << "d3型別 : "<<typeid(d3).name() << endl;
	cout << d3.count() << endl;
}

執行結果:

根據前面介紹的規則,對於9/7和6/5,分子取最大公約數3,分母取最小公倍數35,所以,統一之後的duration為std::chrono::duration<double,struct std::ratio<3,35>>。然後再將原來的duration轉換為統一的duration,最後計算的時鐘週期數為:((9/7)/(3/35)*3)-((6/5)/(3/35)*1),結果為31

2、表示時間點的time_point

time_point表示一個時間點,用來獲取從它的clock的開始所經過的duration(比如,可能是1970.1.1以來的時間間隔)和當前時間,可以做一些時間的比較和算術運算,可以喝ctime庫結合起來顯示時間。time_point必須用clock來計時。time_point有一個函數time_from_eproch()用來獲得1970年1月1日到time_point時間經過的duration

time_point是一個類別範本,原型如下:

template <class Clock, 
class Duration = typename Clock::duration>
class time_point;

template <class Clock, 
class Duration = typename Clock::duration>
class time_point;

第一個模板引數Clock用來指定所要使用的時鐘(標準庫中有三種時鐘,system_clock,steady_clock和high_resolution_clock)
第二個模板函數引數用來表示時間的計量單位(特化的std::chrono::duration<> )

計算當前時間距離1970年1月1日有多少天

#include<iostream>
#include<chrono>
#include<ratio>
using namespace std::chrono;
int main()
{
	using days_type = duration<int, std::ratio<60 * 60 * 24>>;
	time_point<system_clock, days_type> today = time_point_cast<days_type>(system_clock::now());
	std::cout << today.time_since_epoch().count() << " days since epoch" << endl;
}

執行結果:

time_point還支援一些算術運算,比如兩個time_point的差值時鐘週期數,還可以和duration相加減。要注意不同clock的time_point是不能進行算術運算的。下面例子將展示前一天和後一天的日期:

#include<iostream>
#include<chrono>
#include<iomanip>
using namespace std::chrono;
int main()
{
	system_clock::time_point now = system_clock::now();
	std::time_t prev = system_clock::to_time_t(now - hours(24)); //返回時間戳
	std::time_t next = system_clock::to_time_t(now + hours(24)); //返回時間戳

	cout << "One day ago, the time was " << std::put_time(std::localtime(&prev), "%Y.%m.%d %H:%M:%S") << endl;
	cout << "A day later, the time is " << std::put_time(std::localtime(&next), "%Y.%m.%d %H:%M:%S") << endl;	 
}

執行結果:

3、獲取系統時鐘的clocks

clocks表示當前的系統時鐘,內部有time_point、duration、Rep、Period等資訊,主要用來獲取當前時間,以及實現time_t和time_point的相互轉換。clocks包含如下3種時鐘:
-system_clock:代表真實時間的掛鐘時間,具體時間依賴於系統。system_clock保證提供的時間值是一個可讀時間
-steady_clock:不能被“調整” 的時鐘,並不一定代表真實世界的掛鐘時間。保證先後呼叫now()得到的時間值是不會遞減的
-high_resoulution_clock:高精度時鐘,實際上是system_clock或者steady_clock的別名。可以通過now()來獲取當前時間點,程式碼如下:

int main()
{
	std::chrono::system_clock::time_point t1 = std::chrono::system_clock::now();
	cout << "hello fl" << endl;
	std::chrono::system_clock::time_point t2 = std::chrono::system_clock::now();
	cout << (t2 - t1).count() << " tick count" << endl;
	return 0;
}

執行結果:

system_clock的to_time_t方法可以將一個time_point轉換為ctime:

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

而from_time_t方法則正好相反,它將ctime轉換為time_point

steady_clock可以獲取穩定可靠的時間間隔,後一次呼叫now()的值和前一次的差值不會因為修改了系統時間而改變,從而保證了穩定的時間間隔。steady_clock的用法和system用法一樣。

到此這篇關於C++11中的chrono庫詳解的文章就介紹到這了,更多相關C++11中的chrono庫內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com