C++/STL/Chrono
w:C++程式語言中,chrono
是w:標準模板庫(STL)中與時間有關的頭文件(自w:C++11開始)。該頭文件中所有函數與類模板均定義在std::chronow:命名空間中。
概念[編輯]
- duration:時間長度,如1分鐘、2小時、10毫秒等。表示為類模板duration的對象,用一個count representation與一個period precision表示。例如,10毫秒的10為count representation,毫秒為period precision。
- time points:表示一個時間點。例如某人的生日、今天的日出時間等。表示為類模板time_point的對象。用相對於一個固定時間點epoch的duration來表示。
- clocks:時間點相對於真實物理時間的框架。C++11提供了3個clock,C++20還提供了4個clock:
- system_clock:可被管理員手工調整
- steady_clock:不受管理員人為影響,適用於時間流逝的計量
- high_resolution_clock
- utc_clock — UTC時間,包括閏秒
- tai_clock — 國際原子時間,不含閏秒
- gps_clock — GPS時間,不含閏秒
- file_clock — 文件系統時間
類模板[編輯]
時間長度duration[編輯]
表示time span。該類模板聲明為:
template <class Rep, class Period=ratio<1> > class duration;
第一個模板參數為存儲時間計數的數據類型。成員函數count()返回該計數。第二個模板參數表示計數的一個周期,一般是std::ratio類型,表示一個周期(即一個時間嘀嗒tick)是w:秒鐘的倍數或分數,在w:編譯時應為一個w:有理數常量。
duration模板類實例化typedef:
類型 | Rep | Period |
---|---|---|
hours | signed integral至少23比特 | ratio<3600,1> |
minutes | signed integral至少29比特 | ratio<60,1> |
seconds | signed integral至少35比特 | ratio<1,1> |
miliseconds | signed integral至少45比特 | ratio<1,1000> |
microseconds | signed integral至少55比特 | ratio<1,1000000> |
nanoseconds | signed integral至少64比特 | ratio<1,1000000000> |
rep | 對應於模板的第1個參數 | |
period | 對應於模板的第2個參數 |
chrono提供的預定義的時間長度單位都是int64類型的內部存儲數據
- duration模板類成員函數:
- 構造函數
- 析構函數
- count 返回時間嘀嗒計數
- zero: 靜態函數,表示0值
- min:靜態函數,表示最小可能值
- max:靜態函數,表示最大可能值
- operator= 賦值運算符
- operator+ 酉運算符
- operator- 酉運算符
- operator++ 前綴++
- operator++(int) 後綴++
- operator-- 前綴--
- operator--(int) 後綴--
- operator+=
- operator-=
- operator*=
- operator/=
- operator%=
- 非成員函數
- std::common_type<std::chrono::duration> 是類模板std::common_type的特化版本
- operator+
- operator-
- operator*
- operator/
- operator%
- operator==
- operator!=
- operator<
- operator<=
- operator>
- operator>=
- duration_cast 把時間長度轉換到不同時間嘀嗒單位的另一個時間長度。
- floor(std::chrono::duration) w:C++17 轉換時間長度向下近似
- ceil(std::chrono::duration) w:C++17 轉換時間長度向上近似
- round(std::chrono::duration) w:C++17 轉換時間長度向最近偶數近似
- abs(std::chrono::duration) w:C++17 時間長度的絕對值
- 幫助類Helper classes
- treat_as_floating_point 表示一個時間長度可轉換為不同的時間嘀嗒單位
- duration_values 構造給定類型的事件嘀嗒計數的零值、最小值、最大值
w:C++14標準定義的字面量[編輯]
均定義在std::literals::chrono_literals命名空間中。因此需要先聲明using namespace std::chrono_literals;
- operator""h
- operator""min
- operator""s
- operator""ms
- operator""us
- operator""ns
例子[編輯]
為了區分秒數和普通的數值之間的差異,seconds類在設計的時候就禁止了數值隱式轉換為seconds類
seconds s = 3; // 编译出错
seconds s1{3}; // 这样是可以的
s1 = 4; // 编译出错
std::cout << s << "\n"; // 目前还不可以
std::cout << s.count() << "s\n"; // 这样是可以的
seconds s2 = 3s; // C++14支持字面常量
seconds s3 = s2 + s1; // 支持基本的算术操作,但是不支持seconds和一个普通数值进行算术操作
seconds::min(); // 获取秒类型可以表示的范围,
seconds::max();
minutes m1{2};
seconds s2 = m1; // m1隐式转换为seconds
seconds s3 = s2 + m1; // m1隐式转换为seconds,然后运算
//不同时间长度单位的隐式转换必须是向下转换,如minutes转seconds。如果向上转换需用duration_cast显式转换。因为这些转换是截断近似,而不是四舍五入。
seconds s2{1000};
minutes m3 = std::chrono::duration_cast<minutes>(s2);
時間點time_point[編輯]
表示一個時間點,即一個時刻的值。它存儲為從一個固定時刻(epoch)開始的一段時間的長度(duration)。chrono庫中採用的是Unix的時間戳1970年1月1日 00:00。時間點的類模板形如:
template <class Clock,
class Duration = typename Clock::duration>
class time_point {
Duration d_;
public:
using clock = Clock;
using duration = Duration;
// ...
};
- 類型定義
- clock 使用的時鐘
- duration 一個std::chrono::duration類型,用於度量從固定時刻開始的時間的長度
- rep 算術類型,表示時間長度的嘀嗒(tick)數
- period 一個std::ratio類型,表示一個時間嘀嗒的單位
- 成員函數
- (constructor)
- time_since_epoch 返回從固定時刻開始的時間長度。
- operator+= 修改時間長度
- operator-= 修改時間長度
- min 靜態成員函數,最小可能的時間長度
- max 靜態成員函數,最大可能的時間長度
- 非成員函數
- std::common_type<std::chrono::time_point> 是類模板std::common_type的特化版本
- operator+ 修改時間長度
- operator- 修改時間長度
- operator== 比較時間點
- operator!= 比較時間點
- operator< 比較時間點
- operator<= 比較時間點
- operator> 比較時間點
- operator>= 比較時間點
- time_point_cast 函數模板,在同一時鐘下把一個時間點轉化為具有不同時鐘滴答長度的另一個時間點
- floor(std::chrono::time_point) w:C++17 函數模板 轉化時間點並向下近似
- ceil(std::chrono::time_point) w:C++17 函數模板 轉化時間點並向上近似
- round(std::chrono::time_point) w:C++17 函數模板 轉化時間點並近似到最近鄰的偶數
不同類型的時間點之間也可以相互轉換,可隱式的向下轉換;如果向上轉換就必須顯式的使用time_point_cast:
using namespace std::chrono;
template <class D> using sys_time = time_point<system_clock, D>;
sys_time<seconds> tp{5s}; // 5s
sys_time<milliseconds> tp2 = tp; // 5000ms 隐式的向下转换
tp = time_point_cast<seconds>(tp2); // 5s 向下转换,需要显示的使用time_point_cast
時鐘clock[編輯]
語言標準預定義的3個時鐘,形如:
struct some_clock
{
using duration = chrono::duration<int64_t, microseconds>;
using rep = duration::rep;
using period = duration::period;
using time_point = chrono::time_point<some_clock>;
static constexpr bool is_steady = false;
static time_point now() noexcept;
};
不同時鐘的時間點無法相互轉換:
system_clock::time_point tp = system_clock::now();
steady_clock::time_point tp2 = tp; // no viable conversion
Visual C++ 2015把steady_clock都用QueryPerformanceCounter實現;把high_resolution_clock定義為steady_clock的別名。
system_clock[編輯]
當前系統範圍(即對各進程都一致)的一個實時的日曆時鐘(wall clock)。但是這個值並不一定是單調的,因為作業系統可能會修改時間,導致system_clock返回的時間不單調。
- 成員類型:
- rep 表示時鐘滴答計數的算術類型
- period 表示時鐘滴答長度的std::ratio類型,以秒鐘為單位長度
- duration std::chrono::duration<rep, period>
- time_point std::chrono::time_point<std::chrono::high_resolution_clock>
- 成員常量:
- constexpr bool is_steady (public static member constant) 表示該時鐘的每個時間嘀嗒單位是否為均勻(即長度相等) 。
- 成員函數
- now 靜態函數 返回時鐘的當前值,類型為std::chrono::time_point
- to_time_t 靜態函數 把系統時鐘的時間點轉化為C風格的std::time_t
- from_time_t 靜態函數 把C風格的std::time_t轉化為系統時鐘的時間點
steady_clock[編輯]
當前系統實現的一個穩定時鐘。表示的是單調時鐘,隨着物理時間向前,這個時鐘的時間點不會減少,最適合進行間隔的測量。
- 成員類型:
- rep 表示時鐘滴答計數的算術類型
- period 表示時鐘滴答長度的std::ratio類型,以秒鐘為單位長度
- duration std::chrono::duration<rep, period>
- time_point std::chrono::time_point<std::chrono::high_resolution_clock>
- 成員常量:
- constexpr bool is_steady (public static member constant) 表示該時鐘的每個時間嘀嗒單位是否為均勻(即長度相等) 。該值總為true
- 成員函數
- now 靜態函數 返回時鐘的當前值,類型為std::chrono::time_point
high_resolution_clock[編輯]
當前系統實現的一個高解像度時鐘。
- 成員類型:
- rep 表示時鐘滴答計數的算術類型
- period 表示時鐘滴答長度的std::ratio類型,以秒鐘為單位長度
- duration std::chrono::duration<rep, period>
- time_point std::chrono::time_point<std::chrono::high_resolution_clock>
- 成員常量:
- constexpr bool is_steady (靜態) 表示該時鐘的每個時間嘀嗒單位是否為均勻(即長度相等)
- 成員函數
- now 靜態函數 返回時鐘的當前值,類型為std::chrono::time_point
C++20的一個例子[編輯]
// C++20
#include <chrono>
#include <format>
#include <iostream>
int main()
{
using TwentyMins = std::chrono::duration<int, std::ratio<20*60>>;
std::chrono::time_zone const* myTimeZone = std::chrono::current_zone();
std::chrono::time_point p1 = std::chrono::system_clock::now();
std::chrono::time_point p2 = myTimeZone->to_local(p1);
std::chrono::time_point p3 = std::chrono::floor<TwentyMins>(p2);
std::cout << std::format("{:%Y-%m-%d %H:%M}\n", p3);
}
表示為字符串的示例[編輯]
#include <iostream>
#include <chrono>
#include <ratio>
#include <time.h>
#include <iomanip>
#include <sstream>
#include <string>
int main()
{
using namespace std::chrono;
auto now = system_clock::now();
time_t t = system_clock::to_time_t(now);
std::tm tm;
localtime_s(&tm, &t);
auto time = std::put_time(&tm, "%b %d %Y %H:%M:%S");
std::cout << time << std::endl;
std::stringstream ss;
ss << time;
std::string a{ ss.str() };
}
例子[編輯]
時間點的示例[編輯]
#include <iostream>
#include <iomanip>
#include <ctime>
#include <chrono>
int main()
{
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t now_c = std::chrono::system_clock::to_time_t(now - std::chrono::hours(24));
std::cout << "24 hours ago, the time was "
<< std::put_time(std::localtime(&now_c), "%F %T") << '\n';
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
std::cout << "Hello World\n";
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "Printing took "
<< std::chrono::duration_cast<std::chrono::microseconds>(end - start).count()
<< "us.\n";
}
時間長度的示例[編輯]
#include <iostream>
#include <chrono>
int main()
{
using shakes = std::chrono::duration<int, std::ratio<1, 100000000>>;
using jiffies = std::chrono::duration<int, std::centi>;
using microfortnights = std::chrono::duration<float, std::ratio<12096,10000>>;
using nanocenturies = std::chrono::duration<float, std::ratio<3155,1000>>;
std::chrono::seconds sec(1);
std::cout << "1 second is:\n";
std::cout << std::chrono::duration_cast<shakes>(sec).count()
<< " shakes\n";
std::cout << std::chrono::duration_cast<jiffies>(sec).count()
<< " jiffies\n";
std::cout << microfortnights(sec).count() << " microfortnights\n";
std::cout << nanocenturies(sec).count() << " nanocenturies\n";
}
綜合示例[編輯]
#include <iostream>
#include <chrono>
#include <ctime>
long fibonacci(unsigned n)
{
if (n < 2) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
int main()
{
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();
std::cout << "f(42) = " << fibonacci(42) << '\n';
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
std::time_t end_time = std::chrono::system_clock::to_time_t(end);
std::cout << "finished computation at " << std::ctime(&end_time)
<< "elapsed time: " << elapsed_seconds.count() << "s\n";
}