chrono since C++11 庫的參考手冊(英文)| cppreference

chrono 庫定義了三種(直到c++ 20)五種(從c++ 20開始)主要類型以及實用函數和常用類型:
- cokcks
- time points
- durations
- calendar dates (since C++20)
- time zone information (since C++20)
clocks
時鐘由起點(或歷元)和滴答率組成。例如,時鐘的歷元可能是1970年1月1日,并且每秒鐘滴答一次。c++定義了幾種時鐘類型:
| 定義在 |
|
|---|---|
| system_clock | 掛鐘時間來自系統的實時時鐘 |
| steady_clock | 永遠不會被調整的勻速時鐘 |
| ... 更多時鐘類型見: | https://en.cppreference.com/w/cpp/chrono |
epoch
unix時間戳(Unix timestamp)
UNIX時間戳:Unix時間戳(英文為Unix time, POSIX time 或 Unix timestamp)是從 Epoch(1970年1月1日00:00:00 UTC)開始所經過的秒數,不考慮閏秒。
一個小時表示為UNIX時間戳格式為:3600秒;一天表示為UNIX時間戳為86400秒,閏秒不計算。
參考網址:
chrono since C++11 庫的參考手冊(英文)| cppreference
time points
時間點(time point)是從某個特定時鐘的歷元開始的一段時間。
| 定義在 |
|---|
| time_point |
#include <iostream>
#include <chrono>
int main(int argc, char *argv[])
{
auto start = std::chrono::system_clock::now();
std::cout << start << std::endl;
std::cout << start.time_since_epoch() << std::endl;
std::cout
<< std::chrono::duration_cast<std::chrono::seconds>(start.time_since_epoch())
<< std::endl;
std::cout
<< std::chrono::duration_cast<std::chrono::minutes>(start.time_since_epoch())
<< std::endl;
return 0;
}
輸出:
2024-11-17 13:33:22.246335500
1731850402246335500ns
1731850402s
28864173min

使用 chrono 最關鍵的是什么?
- 獲取代碼(一個循環,一個函數)的運行時間
- 得到當前時間
- 格式化顯示時間
- 得到當前時間之后的時間,比如,10秒后,1小時后,一天后,三天后
使用
代碼的執行時間
使用 system_clock 計算代碼的執行時間:
#include<iostream>
#include<chrono>
#include<thread>
int main(int argc, char *argv[])
{
using namespace std::chrono_literals;
auto s = std::chrono::system_clock::now();
std::this_thread::sleep_for(3s);
auto e = std::chrono::system_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::duration<double>>(e-s);
std::cout << diff.count() << std::endl;
return 0;
}
使用 steady_clock 計算代碼的執行時間:
#include <iostream>
#include <chrono>
int main() {
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
// 這里可以放入需要測量執行時間的代碼
for (int i = 0; i < 1000000; ++i) {
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::chrono::duration<double> elapsed_seconds = std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
std::cout << "代碼執行時間: " << elapsed_seconds.count() << "秒" << std::endl;
return 0;
}
得到當前時間
using namespace std;
int main(int argc, char **argv)
{
auto now = chrono::system_clock::now(); // 獲取當前時間戳
// cout << "Now: " << now << endl; // 不能輸出,類型不對
// 將時間戳轉換毫秒數
auto now_ms = chrono::time_point_cast<chrono::milliseconds>(now);
auto value = now_ms.time_since_epoch().count();
cout << "Milliseconds since epoch: " << value << endl;
return 0;
}
格式化顯示時間
c 風格
#include <iostream>
#include <string>
#include <chrono>
#include <ctime>
using namespace std;
int main(int argc, char *argv[])
{
auto tnow = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
auto t = std::gmtime(&tnow);
char buf[100];
auto result = std::strftime(buf, sizeof buf, "%Y-%m-%d", t);
std::cout << buf << std::endl;
return 0;
}
std::gmtime將始于 epoch 的時間轉換為由 Universal Coordinated Time 表示的日歷時,返回值為std::tm*std::tm是一個結構體,用于表示時間:
struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
有以下的幾個問題需要回答:
- t 是一個指針,其資源需要釋放嗎?
- 在C語言中,
std::gmtime函數返回的struct tm*對象不需要手動釋放。該函數將時間戳轉換為協調世界時(UTC)表示的時間結構,返回的指針指向一個靜態分配的內部緩沖區,由標準庫管理內存。每次調用該函數時,這個緩沖區會被覆蓋,因此: - 無需釋放內存:不要使用
free()或類似函數釋放返回的指針,否則會導致未定義行為(如程序崩潰)。 - 數據覆蓋風險:后續調用
gmtime()、localtime()等函數可能會覆蓋該緩沖區的內容,因此建議立即復制數據到自定義的struct tm變量中。 - 線程不安全:
gmtime()在多線程環境中不安全,因為多個線程可能同時修改同一個靜態緩沖區。可使用線程安全的替代函數gmtime_r()(POSIX)或localtime_s()(Windows)。
std::strftime轉換由日歷時表示的日期、時間信息為 null 終結的字符串,依據格格式化字符串進行轉換,最多只有指定數量的字節被寫入結果中。std::size_t strftime( char* str, std::size_t count, const char* format, const std::tm* tp );- str 存儲轉換結果
- count 存儲字節的數量
- format 格式化字符串
- tp 日歷時
- 返回值:轉換的字節數
得到指定的時間點
使用 duration:
#include <iostream>
#include <string>
#include <chrono>
using namespace std;
int main(int argc, char *argv[])
{
auto now = chrono::system_clock::now();
std::chrono::duration<int, std::ratio<1, 1>> d(120);
std::cout << now + d << std::endl; // 兩分鐘后
return 0;
}
使用 chrono literals:
using namespace std::chrono_literals;
auto now = chrono::system_clock::now();
std::cout << now + 10min << std::endl;
| 操作符 | 解釋 | 標準 |
|---|---|---|
| operator""h | a std::chrono::duration literal representing hours | C++14 |
| operator""min | a std::chrono::duration literal representing minutes | C++14 |
| operator""s | a std::chrono::duration literal representing seconds | C++14 |
| operator""ms | a std::chrono::duration literal representing milliseconds | C++14 |
| operator""us | a std::chrono::duration literal representing microseconds | C++14 |
| operator""ns | a std::chrono::duration literal representing nanoseconds | C++14 |
使用 std::duration 表示秒
#include <iostream>
#include <string>
#include <chrono>
using namespace std;
int main(int argc, char *argv[])
{
std::chrono::duration<int, std::ratio<1, 1>> d(30);
//std::cout << d << std::endl;
std::cout << d.count() << std::endl;
return 0;
}
chromo 的實際使用
- 創建一個時鐘:
using namespace std;
int main(int argc, char **argv)
{
auto now = chrono::system_clock::now(); // 獲取當前時間戳
// cout << "Now: " << now << endl; // 不能輸出,類型不對, mingw 不能輸出;msvc 可以;
// 將時間戳轉換毫秒數
auto now_ms = chrono::time_point_cast<chrono::milliseconds>(now);
auto value = now_ms.time_since_epoch().count();
cout << "Milliseconds since epoch: " << value << endl;
return 0;
}
#include <algorithm>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <iostream>
void slow_motion()
{
static int a[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
// Generate Γ(13) == 12! permutations:
while (std::ranges::next_permutation(a).found) {}
}
int main()
{
using namespace std::literals; // enables literal suffixes, e.g. 24h, 1ms, 1s.
const std::chrono::time_point<std::chrono::system_clock> now =
std::chrono::system_clock::now();
const std::time_t t_c = std::chrono::system_clock::to_time_t(now - 24h);
std::cout << "24 hours ago, the time was "
<< std::put_time(std::localtime(&t_c), "%F %T.\n") << std::flush;
const std::chrono::time_point<std::chrono::steady_clock> start =
std::chrono::steady_clock::now();
std::cout << "Different clocks are not comparable: \n"
" System time: " << now.time_since_epoch() << "\n"
" Steady time: " << start.time_since_epoch() << '\n';
slow_motion();
const auto end = std::chrono::steady_clock::now();
std::cout
<< "Slow calculations took "
<< std::chrono::duration_cast<std::chrono::microseconds>(end - start) << " ≈ "
<< (end - start) / 1ms << "ms ≈ " // almost equivalent form of the above, but
<< (end - start) / 1s << "s.\n"; // using milliseconds and seconds accordingly
}
理解 chrono
duration
表示持續時間。
duration 聲明:
template<
class Rep,
class Period = std::ratio<1>
> class duration;
- rep = representing = 表示時間數值的算術類型
秒:
std::duration<int, std::ration<1, 1>> seconds(30); // 30秒
time_point
template<
class Clock,
class Duration = typename Clock::duration
> class time_point;
time_point 表示一個具體的時間,比如 2025-6-25 20:56。它的實現是存儲了從 epoch 開始到指定時間的值,是一個整數,然后經過轉換后得到這樣格式的時間 2025-6-25 20:56。
- clock = 時鐘類型
- duration = 持續時間類型
- representing = 表示,一個用于表示時間數值的算術類型
- period = 周期,比如一分鐘多少秒,這時一分鐘就是一個周期,同樣的,一小時、一天以及一個月等都是一個周期。
period
秒是周期,分鐘是周期,小時是周期,那么最基礎的單位是什么?單位是人規定的,可以有很多個,只是具體數值來根據測量精度來定。如果測量精度是秒,那么沒有更細分的數值,但是單位有。在時間里,以秒周期來說,就是一個數字有多少個秒周期,多余的數值并不會丟失,只是不能轉換為秒(不夠一秒)。
msvc stl 實現:
_EXPORT_STD using nanoseconds = duration<long long, nano>;
_EXPORT_STD using microseconds = duration<long long, micro>;
_EXPORT_STD using milliseconds = duration<long long, milli>;
_EXPORT_STD using seconds = duration<long long>;
_EXPORT_STD using minutes = duration<int, ratio<60>>;
_EXPORT_STD using hours = duration<int, ratio<3600>>;
#if _HAS_CXX20
_EXPORT_STD using days = duration<int, ratio_multiply<ratio<24>, hours::period>>;
_EXPORT_STD using weeks = duration<int, ratio_multiply<ratio<7>, days::period>>;
_EXPORT_STD using years = duration<int, ratio_multiply<ratio<146097, 400>, days::period>>;
_EXPORT_STD using months = duration<int, ratio_divide<years::period, ratio<12>>>;
ratio
msvc stl 實現:
_EXPORT_STD template <intmax_t _Nx, intmax_t _Dx = 1>
struct ratio { // holds the ratio of _Nx to _Dx
static_assert(_Dx != 0, "zero denominator");
static_assert(-INTMAX_MAX <= _Nx, "numerator too negative");
static_assert(-INTMAX_MAX <= _Dx, "denominator too negative");
static constexpr intmax_t num = _Sign_of(_Nx) * _Sign_of(_Dx) * _Abs(_Nx) / _Gcd(_Nx, _Dx);
static constexpr intmax_t den = _Abs(_Dx) / _Gcd(_Nx, _Dx);
using type = ratio<num, den>;
};
- ratio = 比例,得到最簡分式
- numerator,num = 分子
- denominator,den = 分母
_Sing_of得到符號(1 或 -1)_Abs得到絕值
比例:
_EXPORT_STD template <class _Rx1, class _Rx2>
_INLINE_VAR constexpr bool ratio_greater_equal_v = ratio_greater_equal<_Rx1, _Rx2>::value;
_EXPORT_STD using atto = ratio<1, 1000000000000000000LL>;
_EXPORT_STD using femto = ratio<1, 1000000000000000LL>;
_EXPORT_STD using pico = ratio<1, 1000000000000LL>;
_EXPORT_STD using nano = ratio<1, 1000000000>;
_EXPORT_STD using micro = ratio<1, 1000000>;
_EXPORT_STD using milli = ratio<1, 1000>;
_EXPORT_STD using centi = ratio<1, 100>;
_EXPORT_STD using deci = ratio<1, 10>;
_EXPORT_STD using deca = ratio<10, 1>;
_EXPORT_STD using hecto = ratio<100, 1>;
_EXPORT_STD using kilo = ratio<1000, 1>;
_EXPORT_STD using mega = ratio<1000000, 1>;
_EXPORT_STD using giga = ratio<1000000000, 1>;
_EXPORT_STD using tera = ratio<1000000000000LL, 1>;
_EXPORT_STD using peta = ratio<1000000000000000LL, 1>;
_EXPORT_STD using exa = ratio<1000000000000000000LL, 1>;
浙公網安備 33010602011771號