最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++高精度時(shí)間庫<chrono>的實(shí)現(xiàn)示例

 更新時(shí)間:2026年06月04日 08:31:20   作者:樓田莉子  
本文主要介紹了C++高精度時(shí)間庫<chrono>的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

在前面學(xué)習(xí)C語言我們就已經(jīng)學(xué)習(xí)了C語言的時(shí)間庫<time.h>。它操作簡單、是全平臺(tái)行為一致的時(shí)間庫。但是它卻存在著很多的問題——類型不安全,精度較低(通常為秒),擴(kuò)展只能依賴編譯器特制的宏。

而現(xiàn)代項(xiàng)目中如果要進(jìn)行性能測試、時(shí)間間隔計(jì)算的話,C語言的<time.h>顯然是不夠的。因此在C++11中,引入了<chrono>這個(gè)時(shí)間庫。接下來我們就來一次學(xué)習(xí)一下。

相關(guān)的英文文檔為:Standard library header <chrono> (C++11) - cppreference.com

<chrono>設(shè)計(jì)哲學(xué)

在C++11之前,我們處理時(shí)間基本靠 time_t、clock() 和 struct timespec。這種方式的問題在于:類型不安全。函數(shù)參數(shù)傳遞 time_t,你無法直觀知道單位是秒還是毫秒;做時(shí)間運(yùn)算時(shí),極易因單位混淆導(dǎo)致bug

 <chrono> 庫最偉大的貢獻(xiàn),就是引入了 編譯期類型安全 和 精度無關(guān) 的時(shí)間處理模型。它將時(shí)間抽象為三個(gè)核心概念:

  • 時(shí)間段 (Duration):由 數(shù)值 和 單位 組成的強(qiáng)類型。例如 std::chrono::seconds(10) 就是10秒,std::chrono::milliseconds(1000) 是1000毫秒,它們?cè)陬愋蜕暇筒煌?,不能直接隱式轉(zhuǎn)換,避免了單位混淆。
  • 時(shí)間點(diǎn) (Time Point):某個(gè)特定時(shí)鐘上的一個(gè)點(diǎn),由 時(shí)鐘 (Clock) 和 時(shí)間段 (Duration) 共同定義。它本質(zhì)上是從某個(gè)固定的紀(jì)元 (Epoch) 開始到現(xiàn)在的時(shí)間段。例如 std::chrono::system_clock::now() 返回的就是一個(gè)時(shí)間點(diǎn)。
  • 時(shí)鐘 (Clock):提供了獲取當(dāng)前時(shí)間點(diǎn)的入口 (now()),并定義了時(shí)間點(diǎn)的精度和紀(jì)元。標(biāo)準(zhǔn)提供了三種時(shí)鐘(如文檔所列),這是新手最容易踩坑的地方,下面我會(huì)重點(diǎn)講。

庫中的單位

時(shí)長單位(Duration Units)

這些是表示時(shí)間間隔的類型,基于duration模板定義。

單位名稱引入標(biāo)準(zhǔn)說明
std::chrono::nanosecondsC++11納秒,周期為std::nano
std::chrono::microsecondsC++11微秒,周期為std::micro
std::chrono::millisecondsC++11毫秒,周期為std::milli
std::chrono::secondsC++11秒,周期為std::ratio<1>
std::chrono::minutesC++11分鐘,周期為std::ratio<60>
std::chrono::hoursC++11小時(shí),周期為std::ratio<3600>
std::chrono::daysC++20天,周期為std::ratio<86400>
std::chrono::weeksC++20周,周期為std::ratio<604800>
std::chrono::monthsC++20月(平均格里高利月),周期為std::ratio<2629746>
std::chrono::yearsC++20年(平均格里高利年),周期為std::ratio<31556952>

時(shí)鐘單位(Clock Types)

時(shí)鐘定義了時(shí)間的原點(diǎn)(紀(jì)元)和刻度,用于產(chǎn)生時(shí)間點(diǎn)。

時(shí)鐘名稱引入標(biāo)準(zhǔn)說明
std::chrono::system_clockC++11系統(tǒng)范圍實(shí)時(shí)時(shí)鐘(掛鐘時(shí)間),通?;赨nix時(shí)間戳
std::chrono::steady_clockC++11單調(diào)時(shí)鐘,不受系統(tǒng)時(shí)間調(diào)整影響,適合測量間隔
std::chrono::high_resolution_clockC++11當(dāng)前設(shè)置下最高精度的時(shí)鐘,通常是上述之一的別名
std::chrono::utc_clockC++20協(xié)調(diào)世界時(shí)(UTC),處理跳秒
std::chrono::tai_clockC++20國際原子時(shí)(TAI),與UTC有固定偏移且無跳秒
std::chrono::gps_clockC++20全球定位系統(tǒng)時(shí)(GPS),始于1980-01-06
std::chrono::file_clockC++20文件系統(tǒng)使用的時(shí)鐘別名,用于獲取文件時(shí)間戳
std::chrono::local_tC++20偽時(shí)鐘,代表本地時(shí)間,不關(guān)聯(lián)具體時(shí)區(qū)

日歷基礎(chǔ)單位(Calendar Fundamentals)

C++20引入,表示格里高利歷中的基本日期元素。

類型名稱引入標(biāo)準(zhǔn)說明
std::chrono::dayC++20表示月份中的某一天(1-31)
std::chrono::monthC++20表示年份中的某個(gè)月(1-12)
std::chrono::yearC++20表示格里高利歷中的年份(如2024)
std::chrono::weekdayC++20表示星期幾(0代表周日,1周一,...6周六)
std::chrono::last_specC++20標(biāo)簽類,用于表示月份的最后一天或最后一個(gè)工作日

日歷復(fù)合單位(Calendar Composites)

由基礎(chǔ)類型組合而成,用于表示完整的日期或特定規(guī)則。

類型名稱引入標(biāo)準(zhǔn)說明
std::chrono::year_monthC++20特定的年+月組合(如2024y/May)
std::chrono::month_dayC++20特定的月+日組合(如May/21d),忽略年份
std::chrono::year_month_dayC++20完整的日期(如2024-05-21)
std::chrono::year_month_day_lastC++20某月的最后一天(如2024年5月的最后一天)
std::chrono::month_day_lastC++20某月的最后一天,忽略年份
std::chrono::year_month_weekdayC++20某年第N個(gè)月的星期W(如2024年5月的第3個(gè)星期二)
std::chrono::year_month_weekday_lastC++20某個(gè)月的最后一個(gè)星期W
std::chrono::month_weekdayC++20某個(gè)月的第N個(gè)星期W,忽略年份
std::chrono::month_weekday_lastC++20某個(gè)月的最后一個(gè)星期W,忽略年份
std::chrono::weekday_indexedC++20表示某個(gè)月的第幾個(gè)星期幾(如第3個(gè)星期二)
std::chrono::weekday_lastC++20表示某個(gè)月的最后一個(gè)星期幾

時(shí)刻單位(Time of Day)

將時(shí)長拆分為時(shí)、分、秒等,用于表示一天內(nèi)的時(shí)間。

類型名稱引入標(biāo)準(zhǔn)說明
std::chrono::hh_mm_ssC++20將時(shí)長拆分為小時(shí):分鐘:秒及亞秒的模板類,支持12小時(shí)/24小時(shí)格式

時(shí)區(qū)單位(Time Zone)

C++20引入,用于處理時(shí)區(qū)、本地時(shí)間和轉(zhuǎn)換。

類型名稱引入標(biāo)準(zhǔn)說明
std::chrono::time_zoneC++20代表一個(gè)IANA時(shí)區(qū)(如"Asia/Shanghai")
std::chrono::zoned_timeC++20將時(shí)區(qū)與時(shí)間點(diǎn)關(guān)聯(lián)的組合類型
std::chrono::tzdbC++20IANA時(shí)區(qū)數(shù)據(jù)庫的快照
std::chrono::sys_infoC++20特定時(shí)間點(diǎn)在某個(gè)時(shí)區(qū)的詳細(xì)信息(偏移量、縮寫、是否DST)
std::chrono::local_infoC++20描述本地時(shí)間到系統(tǒng)時(shí)間轉(zhuǎn)換的低級(jí)信息(用于處理歧義或不存在的時(shí)間)
std::chrono::chooseC++20枚舉,用于指定在本地時(shí)間歧義時(shí)如何選擇(earliest或latest)
std::chrono::time_zone_linkC++20時(shí)區(qū)的替代名稱(鏈接)
std::chrono::nonexistent_local_timeC++20異常,表示本地時(shí)間不存在(如夏令時(shí)快進(jìn)時(shí)段)
std::chrono::ambiguous_local_timeC++20異常,表示本地時(shí)間有歧義(如夏令時(shí)回?fù)軙r(shí)段)

字面量單位(Literals)

定義在std::literals::chrono_literals內(nèi)聯(lián)命名空間中,用于便捷書寫。

字面量運(yùn)算符引入標(biāo)準(zhǔn)返回類型/說明
operator""hC++14返回std::chrono::duration,表示小時(shí)
operator""minC++14返回std::chrono::duration,表示分鐘
operator""sC++14返回std::chrono::duration,表示秒
operator""msC++14返回std::chrono::duration,表示毫秒
operator""usC++14返回std::chrono::duration,表示微秒
operator""nsC++14返回std::chrono::duration,表示納秒
operator""yC++20返回std::chrono::year,表示年份

模板類

std::chrono::duration

這是最核心的類模板,它將一個(gè)數(shù)值(tick數(shù))和一個(gè)時(shí)間單位(tick周期)綁定在一起,實(shí)現(xiàn)了類型安全的時(shí)間長度表示。

template<class Rep,class Period = std::ratio<1>> 
class duration;
  • Rep:存儲(chǔ)tick計(jì)數(shù)的算術(shù)類型,如 long long、int 或 double。
  • Period:一個(gè) std::ratio 類型,編譯期指定每個(gè)tick代表的秒數(shù)。例如,std::ratio<1> 為1秒,std::milli 為1/1000秒。

 核心接口與表達(dá)式

接口類別表達(dá)式/代碼示例作用與說明
構(gòu)造函數(shù)duration<Rep, Period> d(5);用tick計(jì)數(shù)值構(gòu)造時(shí)長。通常通過預(yù)定義類型或字面量創(chuàng)建,如 5s、100ms。
觀察值d.count()返回底層的tick計(jì)數(shù)值(Rep類型)。
算術(shù)運(yùn)算d1 + d2, d1 - d2時(shí)長之間加減,返回相同單位的時(shí)長。
d * 3, d / 2時(shí)長乘以或除以一個(gè)標(biāo)量(Rep類型)。
比較運(yùn)算d1 == d2, d1 < d2比較兩個(gè)時(shí)長的長短(自動(dòng)處理不同單位)。
單位轉(zhuǎn)換duration_cast<seconds>(d)顯式將時(shí)長轉(zhuǎn)換為其他單位(可能截?cái)啵?/td>
duration<double>(d)若目標(biāo) Rep 為浮點(diǎn)數(shù),可隱式轉(zhuǎn)換(無需cast)。
特殊值duration::zero()返回零長度的時(shí)長。
duration::min()返回該時(shí)長類型能表示的最小值(最負(fù)值)。
duration::max()返回該時(shí)長類型能表示的最大值。

示例代碼:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<chrono>
#include <ratio>//提供編譯期有理數(shù)算術(shù)的支持。
using namespace std::chrono;
//duration 的基本操作
void TestDuration()
{
    // 1. 構(gòu)造與觀察
    milliseconds ms(1024);           // 1024毫秒
    std::cout << ms.count() << " ms\n"; // 輸出: 1024 ms
    // 2. 算術(shù)運(yùn)算
    seconds s = duration_cast<seconds>(milliseconds(2500) + milliseconds(500));
    std::cout << s.count() << " s\n"; // 輸出 3 s
    // 3. 比較運(yùn)算
    if (minutes(1) > seconds(30)) 
    {
        std::cout << "1分鐘比30秒長\n";
    }
    // 4. 單位轉(zhuǎn)換
    seconds s2 = duration_cast<seconds>(milliseconds(1500)); // 顯式轉(zhuǎn)換: 1s
    std::cout << s2.count() << " s (截?cái)嗪?\n"; // 輸出: 1 s
    duration<double, std::ratio<60>> d_min = seconds(90); // 隱式轉(zhuǎn)換: 1.5分鐘
    std::cout << d_min.count() << " 分鐘\n"; // 輸出: 1.5 分鐘
    // 5. 特殊值
    std::cout << "duration<int>::zero(): " << duration<int>::zero().count() << "\n";
}

結(jié)果為:

std::chrono::treat_as_floating_point

這是一個(gè)類型特征(type trait),用于判斷一個(gè)類型是否應(yīng)被視為浮點(diǎn)數(shù),從而決定是否允許從高精度到低精度的隱式轉(zhuǎn)換。

//C++11定義
template< class Rep >
struct treat_as_floating_point : std::is_floating_point<Rep> {};

//C++17定義
template< class Rep >
constexpr bool treat_as_floating_point_v = treat_as_floating_point<Rep>::value;

它繼承自 std::is_floating_point,因此默認(rèn)情況下,只有當(dāng) Rep 是 floatdouble、long double 時(shí),其值為 true。

核心規(guī)則與表達(dá)式

表達(dá)式值示例作用與說明
treat_as_floating_point_v<int>false指示 int 不被視為浮點(diǎn)數(shù)。
treat_as_floating_point_v<double>true指示 double 被視為浮點(diǎn)數(shù)。
編譯期分支if constexpr (treat_as_floating_point_v<Rep>)在模板編程中,根據(jù)此特征選擇不同的實(shí)現(xiàn)路徑。
控制隱式轉(zhuǎn)換duration<double, milli> d = seconds(1);允許:因?yàn)槟繕?biāo)Rep為double,treat_as_floating_point為true,1秒隱式轉(zhuǎn)為1000.0毫秒。
duration<int, milli> d = seconds(1);禁止(編譯錯(cuò)誤):因?yàn)槟繕?biāo)Rep為int,treat_as_floating_point為false,隱式轉(zhuǎn)換可能截?cái)鄶?shù)據(jù),必須用 duration_cast。

示例代碼:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<chrono>
#include <ratio>//提供編譯期有理數(shù)算術(shù)的支持。
using namespace std::chrono;
//treat_as_floating_point 
void TestTAFP()
{
    // 檢查特征值
    std::cout << std::boolalpha;
    std::cout << "treat_as_floating_point<int>: "
        << treat_as_floating_point<int>::value << "\n";   // false
    std::cout << "treat_as_floating_point<double>: "
        << treat_as_floating_point<double>::value << "\n"; // true
    // 演示其對(duì)轉(zhuǎn)換的影響
    seconds s(1); // 1秒
    // 1. 目標(biāo)為 double (treat_as_floating_point == true) -> 隱式轉(zhuǎn)換 OK
    duration<double, std::milli> d1 = s; // 自動(dòng)變?yōu)?1000.0 毫秒
    std::cout << "d1 (double毫秒): " << d1.count() << " ms\n";
    // 2. 目標(biāo)為 int (treat_as_floating_point == false) -> 隱式轉(zhuǎn)換 ERROR
    // duration<int, milli> d2 = s; // 編譯錯(cuò)誤: 存在截?cái)囡L(fēng)險(xiǎn)
    // 3. 必須顯式轉(zhuǎn)換
    duration<int, std::milli> d2 = duration_cast<milliseconds>(s);
    std::cout << "d2 (int毫秒, 顯式轉(zhuǎn)換): " << d2.count() << " ms\n";
}

結(jié)果為:

std::chrono::duration_values

這是一個(gè)工具類模板,它為給定的 Rep 類型提供了獲取零值、最小值和最大值的統(tǒng)一靜態(tài)接口。

template<class Rep>
struct duration_values;

核心靜態(tài)接口與表達(dá)式

靜態(tài)函數(shù)表達(dá)式示例作用與說明
zero()duration_values<Rep>::zero()返回 Rep 類型的零值表示。通常為 Rep(0)。
min()duration_values<Rep>::min()返回 Rep 類型能表示的最?。ㄗ钬?fù))值。
max()duration_values<Rep>::max()返回 Rep 類型能表示的最大值。

主要用途:它主要被標(biāo)準(zhǔn)庫內(nèi)部用于實(shí)現(xiàn) duration::zero()、duration::min() 和 duration::max() 成員函數(shù)。例如,duration::zero() 的實(shí)現(xiàn)通常會(huì)返回 duration(duration_values<Rep>::zero())。

自定義類型支持:如果你想用自定義類型(如高精度有理數(shù)類)作為 duration 的 Rep,可以通過特化 duration_values 來告知標(biāo)準(zhǔn)庫如何獲取該類型的這些邊界值,從而使你的類型能與 <chrono 無縫協(xié)作。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<chrono>
#include <ratio>//提供編譯期有理數(shù)算術(shù)的支持。
using namespace std::chrono;
void TestDurationV()
{
    // 1. 獲取基本類型的邊界值
    std::cout << "duration_values<int>::zero(): "
        << duration_values<int>::zero() << "\n";
    std::cout << "duration_values<int>::min(): "
        << duration_values<int>::min() << "\n";
    std::cout << "duration_values<int>::max(): "
        << duration_values<int>::max() << "\n";

    std::cout << "duration_values<double>::zero(): "
        << duration_values<double>::zero() << "\n";
    std::cout << "duration_values<double>::min(): "
        << duration_values<double>::min() << "\n";
    std::cout << "duration_values<double>::max(): "
        << duration_values<double>::max() << "\n";

    // 2. 它們與 duration 的成員函數(shù)返回的時(shí)長對(duì)象的關(guān)系
    // 以下兩者本質(zhì)上是等價(jià)的
    auto zero_dur1 = duration<int>::zero(); // 返回 duration<int> 對(duì)象
    auto zero_dur2 = duration<int>(duration_values<int>::zero()); // 顯式構(gòu)造

    std::cout << "duration<int>::zero().count(): "
        << zero_dur1.count() << "\n";
    std::cout << "手動(dòng)構(gòu)造的零時(shí)長 count(): "
        << zero_dur2.count() << "\n";
}

結(jié)果為:

時(shí)間點(diǎn)

time_point

 這是最核心的類模板,它將一個(gè)時(shí)鐘(Clock)和一個(gè)時(shí)長(Duration)結(jié)合起來,表示相對(duì)于該時(shí)鐘紀(jì)元(epoch)的一個(gè)具體時(shí)間點(diǎn)。

template<class Clock, class Duration = typename Clock::duration>
class time_point;
  • Clock:關(guān)聯(lián)的時(shí)鐘類型,如 system_clock、steady_clock。它定義了時(shí)間點(diǎn)的原點(diǎn)(紀(jì)元)。
  • Duration:用于度量從紀(jì)元到該時(shí)間點(diǎn)的時(shí)長的類型,默認(rèn)為時(shí)鐘的 duration 類型(通常是 microseconds 或 nanoseconds)。

核心接口與表達(dá)式

接口類別表達(dá)式/代碼示例作用與說明
構(gòu)造函數(shù)time_point<Clock, Duration> tp;默認(rèn)構(gòu)造,創(chuàng)建一個(gè)值初始化的時(shí)間點(diǎn)(對(duì)于某些時(shí)鐘,表示其紀(jì)元)。
time_point<Clock, Duration> tp(d);用 duration(從紀(jì)元開始的時(shí)長)構(gòu)造一個(gè)時(shí)間點(diǎn)。
獲取時(shí)長tp.time_since_epoch()核心觀察函數(shù)。返回一個(gè) Duration 類型的值,表示從時(shí)鐘紀(jì)元到 tp 的時(shí)間長度。
算術(shù)運(yùn)算tp + d, tp - d時(shí)間點(diǎn) ± 時(shí)長 = 新的時(shí)間點(diǎn)。d 是 duration 類型。
tp1 - tp2兩個(gè)時(shí)間點(diǎn)相減,得到一個(gè) duration 對(duì)象,表示它們之間的時(shí)間間隔。要求兩個(gè)時(shí)間點(diǎn)使用相同的時(shí)鐘。
比較運(yùn)算tp1 == tp2, tp1 < tp2比較兩個(gè)時(shí)間點(diǎn)的先后順序(要求相同時(shí)鐘)。
單位轉(zhuǎn)換time_point_cast<duration>(tp)將時(shí)間點(diǎn)的內(nèi)部時(shí)長單位顯式轉(zhuǎn)換為另一種 duration 類型(可能截?cái)啵?/td>
floor<duration>(tp), ceil<duration>(tp)(C++17/20) 將時(shí)間點(diǎn)向下、向上取整到指定的時(shí)長精度。
特殊值time_point::min()返回該時(shí)鐘能表示的最早時(shí)間點(diǎn)(通常是非常久遠(yuǎn)的過去)。
time_point::max()返回該時(shí)鐘能表示的最晚時(shí)間點(diǎn)。

示例代碼:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <chrono>
#include <thread>

using namespace std::chrono;

void TestTimePoint()
{
    // 1. 獲取當(dāng)前時(shí)間點(diǎn)(基于 system_clock)
    system_clock::time_point now = system_clock::now();
    std::cout << "當(dāng)前時(shí)間點(diǎn)已獲取\n";

    // 2. 獲取從紀(jì)元到現(xiàn)在的時(shí)長
    auto since_epoch = now.time_since_epoch();
    std::cout << "從紀(jì)元至今已過去 "
        << duration_cast<seconds>(since_epoch).count() << " 秒\n";

    // 3. 時(shí)間點(diǎn)算術(shù):計(jì)算 1 小時(shí)后的時(shí)間點(diǎn)
    system_clock::time_point one_hour_later = now + hours(1);
    std::cout << "1 小時(shí)后的時(shí)間點(diǎn)已計(jì)算\n";

    // 4. 時(shí)間點(diǎn)減法:計(jì)算兩個(gè)時(shí)間點(diǎn)的間隔
    auto diff = one_hour_later - now;
    std::cout << "時(shí)間間隔為 " << duration_cast<minutes>(diff).count() << " 分鐘\n";

    // 5. 時(shí)間點(diǎn)比較
    if (one_hour_later > now) 
    {
        std::cout << "1小時(shí)后確實(shí)晚于現(xiàn)在\n";
    }

    // 6. 單位轉(zhuǎn)換示例
    auto now_ms = time_point_cast<milliseconds>(now);
    std::cout << "當(dāng)前時(shí)間點(diǎn)的毫秒精度計(jì)數(shù): "
        << now_ms.time_since_epoch().count() << " ms\n";

    // 7. 休眠示例(演示時(shí)間點(diǎn)與實(shí)際等待)
    auto start = steady_clock::now();
    std::this_thread::sleep_for(milliseconds(100));
    auto end = steady_clock::now();
    std::cout << "休眠了 "
        << duration_cast<microseconds>(end - start).count()
        << " 微秒\n";

}

結(jié)果為:

clock_time_conversion

這是一個(gè)特性類(trait),它提供了在不同時(shí)鐘的時(shí)間點(diǎn)之間進(jìn)行轉(zhuǎn)換的機(jī)制。在C++20中,隨著新時(shí)鐘(如 utc_clock)的引入,這個(gè)類變得尤為重要。標(biāo)準(zhǔn)庫通過特化為特定的時(shí)鐘對(duì)提供轉(zhuǎn)換邏輯。

template<class Dest, class Source> 
struct clock_time_conversion;
  • Dest 和 Source:通常是時(shí)鐘類型。這個(gè)模板本身沒有定義通用的轉(zhuǎn)換,而是通過為特定的時(shí)鐘對(duì)提供特化來實(shí)現(xiàn)轉(zhuǎn)換邏輯。

核心接口與表達(dá)式

這個(gè)類的主要接口是一個(gè)函數(shù)調(diào)用運(yùn)算符(operator()),它接受一個(gè)源時(shí)鐘的時(shí)間點(diǎn),并返回目標(biāo)時(shí)鐘的時(shí)間點(diǎn)(或是一個(gè)能轉(zhuǎn)換為時(shí)間點(diǎn)的類型,如 sys_time)。

表達(dá)式作用與說明
通用形式clock_time_conversion<Dest, Source>{} 創(chuàng)建一個(gè)轉(zhuǎn)換器對(duì)象。
converter(tp_source) 執(zhí)行實(shí)際的轉(zhuǎn)換。
C++20 常用轉(zhuǎn)換示例clock_time_conversion<system_clock, utc_clock>{}(utc_tp):將 utc_time 轉(zhuǎn)換為 sys_time。
clock_time_conversion<utc_clock, system_clock>{}(sys_tp):將 sys_time 轉(zhuǎn)換為 utc_time。
clock_time_conversion<system_clock, tai_clock>{}(tai_tp):將 tai_time 轉(zhuǎn)換為 sys_time。
便捷函數(shù)clock_cast<Dest>(tp_source) (C++20):這是 clock_time_conversion 的簡化包裝,使用更直觀。例如 clock_cast<utc_clock>(sys_tp)。

示例代碼:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <chrono>
#include <thread>

using namespace std::chrono;

void TestCTC()
{
    // 獲取當(dāng)前系統(tǒng)時(shí)間點(diǎn)(UTC 時(shí)間)
    auto sys_now = system_clock::now();

    // 1. 使用 clock_cast 將系統(tǒng)時(shí)間轉(zhuǎn)換為 UTC 時(shí)鐘的時(shí)間點(diǎn)
    utc_clock::time_point utc_now = clock_cast<utc_clock>(sys_now);
    std::cout << "系統(tǒng)時(shí)間已轉(zhuǎn)換為 UTC 時(shí)間\n";

    // 2. 使用 clock_time_conversion 直接進(jìn)行轉(zhuǎn)換(等價(jià)于 clock_cast)
    clock_time_conversion<utc_clock, system_clock> converter;
    utc_clock::time_point utc_now2 = converter(sys_now);
    std::cout << "使用轉(zhuǎn)換器再次轉(zhuǎn)換成功\n";

    // 3. 轉(zhuǎn)換回系統(tǒng)時(shí)間
    auto sys_now2 = clock_cast<system_clock>(utc_now);
    if (sys_now == sys_now2) 
    {
        std::cout << "往返轉(zhuǎn)換后時(shí)間點(diǎn)一致\n";
    }

    // 4. 與 TAI 時(shí)間互轉(zhuǎn)(展示不同時(shí)鐘系統(tǒng))
    tai_clock::time_point tai_now = clock_cast<tai_clock>(sys_now);
    std::cout << "系統(tǒng)時(shí)間已轉(zhuǎn)換為 TAI 時(shí)間\n";

    // 計(jì)算當(dāng)前 UTC 和 TAI 的偏移(通常為 37 秒,因跳秒而變)
    auto offset = tai_now - clock_cast<tai_clock>(utc_now);
    std::cout << "當(dāng)前 UTC 與 TAI 偏移: "
        << duration_cast<seconds>(offset).count() << " 秒\n";
}

結(jié)果為:

時(shí)鐘

在 <chrono 中,一個(gè)時(shí)鐘類通常提供以下核心接口(以靜態(tài)成員的形式):

接口表達(dá)式作用與說明
當(dāng)前時(shí)間點(diǎn)clock::now()靜態(tài)成員函數(shù),返回當(dāng)前時(shí)刻的 time_point。這是最常用的接口。
時(shí)間點(diǎn)類型clock::time_point該時(shí)鐘專屬的時(shí)間點(diǎn)類型,通常是 time_point<clock> 的別名。
時(shí)長類型clock::duration該時(shí)鐘的“原生”精度(tick周期),通常是 duration 的別名,如 microseconds。
周期類型clock::period即 duration 的 Period 模板參數(shù),一個(gè) ratio 類型,表示 tick 周期(秒)。
是否穩(wěn)定clock::is_steady布爾值常量。true 表示該時(shí)鐘是單調(diào)的(不會(huì)向后調(diào)整),適合測量時(shí)間間隔。

C++11 的基礎(chǔ)三時(shí)鐘

這三個(gè)時(shí)鐘從 C++11 起就存在,覆蓋了絕大多數(shù)日常使用場景。

時(shí)鐘名稱核心特性典型用途是否穩(wěn)定 (is_steady)
system_clock表示系統(tǒng)實(shí)時(shí)時(shí)鐘(掛鐘時(shí)間),通?;?Unix 時(shí)間戳(1970-01-01 00:00:00 UTC)。獲取當(dāng)前日期時(shí)間、與日歷交互、需要存儲(chǔ)或展示給用戶的時(shí)間。通常為 false(管理員可修改系統(tǒng)時(shí)間)
steady_clock單調(diào)時(shí)鐘,保證只能向前移動(dòng),不受系統(tǒng)時(shí)間調(diào)整影響。測量時(shí)間間隔、性能測試、超時(shí)計(jì)時(shí)。true
high_resolution_clock當(dāng)前設(shè)置下具有最高精度的時(shí)鐘。通常是 system_clock 或 steady_clock 的別名。需要最高精度計(jì)時(shí)的場景(但請(qǐng)注意,精度和穩(wěn)定性需查閱具體實(shí)現(xiàn))。取決于其底層別名

示例代碼:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <chrono>
#include <thread>
using namespace std::chrono;
//C++11的基礎(chǔ)時(shí)鐘
void TestClocks11()
{
    // 1. system_clock: 獲取當(dāng)前時(shí)間點(diǎn)并轉(zhuǎn)換為可讀形式
    auto sys_now = system_clock::now();
    std::time_t sys_now_c = system_clock::to_time_t(sys_now);
    std::cout << "system_clock 當(dāng)前時(shí)間: " << std::ctime(&sys_now_c);
    // 2. steady_clock: 測量代碼塊執(zhí)行時(shí)間
    auto start = steady_clock::now();
    std::this_thread::sleep_for(milliseconds(100)); // 模擬工作
    auto end = steady_clock::now();
    auto elapsed = duration_cast<microseconds>(end - start);
    std::cout << "steady_clock 測量耗時(shí): " << elapsed.count() << " us\n";
    // 3. high_resolution_clock: 最高精度計(jì)時(shí)(用法與 steady_clock 類似)
    auto hr_start = high_resolution_clock::now();
    // ... 一些工作 ...
    auto hr_end = high_resolution_clock::now();
    auto hr_elapsed = duration_cast<nanoseconds>(hr_end - hr_start);
    std::cout << "high_resolution_clock 耗時(shí): " << hr_elapsed.count() << " ns\n";
    // 4. 檢查時(shí)鐘的穩(wěn)定性
    std::cout << std::boolalpha;
    std::cout << "system_clock 是否穩(wěn)定: " << system_clock::is_steady << "\n";
    std::cout << "steady_clock 是否穩(wěn)定: " << steady_clock::is_steady << "\n";
}

結(jié)果為:

C++20 新增的專業(yè)時(shí)鐘

C++20 極大地?cái)U(kuò)展了時(shí)鐘家族,引入了處理不同時(shí)間標(biāo)準(zhǔn)的能力,主要面向科學(xué)計(jì)算、衛(wèi)星通信等專業(yè)領(lǐng)域。

時(shí)鐘名稱核心特性與用途
utc_clock協(xié)調(diào)世界時(shí)(UTC)。它處理跳秒(leap second),能精確表示閏秒時(shí)刻。now() 返回 utc_time。
tai_clock國際原子時(shí)(TAI)。它是連續(xù)的時(shí)間尺度,沒有跳秒,與 UTC 有固定偏移(當(dāng)前為 37 秒)。
gps_clock全球定位系統(tǒng)時(shí)(GPS)。它與 TAI 有固定偏移(TAI = GPS + 19 秒),起點(diǎn)為 1980-01-06。
file_clock用于文件系統(tǒng)時(shí)間戳的時(shí)鐘別名。它提供了與 system_clock 相互轉(zhuǎn)換的便捷方法 to_sys()/from_sys(),以處理不同操作系統(tǒng)的文件時(shí)間紀(jì)元。
local_t這是一個(gè)偽時(shí)鐘(pseudo-clock),它本身不提供 now() 函數(shù)。它用于標(biāo)記一個(gè)時(shí)間點(diǎn)是與本地時(shí)間(未指定時(shí)區(qū))關(guān)聯(lián)的,需要配合時(shí)區(qū)庫(如 zoned_time)才有實(shí)際意義。

示例代碼:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <chrono>
#include <thread>
using namespace std::chrono;
//C++20的時(shí)鐘
void TestClocks20()
{
    // 1. 獲取當(dāng)前 UTC 時(shí)間
    auto utc_now = utc_clock::now();
    std::cout << "UTC 時(shí)間已獲取\n";

    // 2. 獲取當(dāng)前 TAI 時(shí)間
    auto tai_now = tai_clock::now();
    std::cout << "TAI 時(shí)間已獲取\n";

    // 3. 時(shí)鐘轉(zhuǎn)換 (C++20 的 clock_cast)
    auto sys_from_utc = clock_cast<system_clock>(utc_now);
    auto sys_from_tai = clock_cast<system_clock>(tai_now);

    std::cout << "UTC 和 TAI 時(shí)間已轉(zhuǎn)換為 system_clock\n";

    // 4. file_clock 的使用
    auto file_now = file_clock::now();
    auto sys_from_file = clock_cast<system_clock>(file_now); // 或 clock_cast<system_clock>
    std::cout << "文件時(shí)間已轉(zhuǎn)換為系統(tǒng)時(shí)間\n";

    // 5. 注意:local_t 不能直接調(diào)用 now()
    // auto local_now = local_t::now(); // 編譯錯(cuò)誤
    // 它通常與 zoned_time 配合使用
}

示例代碼:

輔助模板:is_clock與is_clock_v

這是 C++20 引入的一個(gè)類型特征,用于在編譯期判斷一個(gè)類型是否符合時(shí)鐘的要求。

表達(dá)式作用與說明
is_clock<T>::value如果類型 T 滿足時(shí)鐘的所有要求(嵌套類型 duration、rep、period、time_point 以及靜態(tài)函數(shù) now() 等),則為 true。
is_clock_v<T>輔助變量模板,等同于 is_clock<T>::value。

示例代碼:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <chrono>
#include <thread>
using namespace std::chrono;
//C++20輔助模板——檢測是否為時(shí)鐘類型
class MYclass
{};
void TestCheck()
{
    std::cout << std::boolalpha;
    std::cout << "is_clock_v<system_clock>: "
        << std::chrono::is_clock_v<std::chrono::system_clock> << "\n"; // true
    std::cout << "is_clock_v<MYclass>: "
        << std::chrono::is_clock_v<MYclass> << "\n"; // false
}

結(jié)果為:

日歷

日歷基礎(chǔ)類型

這些是構(gòu)成日期的基本原子類型,每個(gè)都封裝了特定的日歷字段。

類型名稱引入標(biāo)準(zhǔn)核心接口與表達(dá)式作用與說明
dayC++20day d(21);構(gòu)造一個(gè)表示某日的對(duì)象(1-31)。
d.ok()檢查該日是否有效(如 2月30日返回 false)。
d == day(21)比較兩個(gè)日是否相等。
d += days(1)日期的加減運(yùn)算(會(huì)進(jìn)位到月份)。
monthC++20month m(5); 或 month m = May;構(gòu)造一個(gè)表示某月的對(duì)象(1-12)。標(biāo)準(zhǔn)庫提供了 January 到 December 常量。
m.ok()檢查月份是否在有效范圍(1-12)。
m == May比較月份。
yearC++20year y(2024); 或 2024y(字面量)構(gòu)造一個(gè)表示年份的對(duì)象。
y.is_leap()判斷該年是否為閏年。
y.ok()檢查年份是否在 [-32767, 32767] 范圍內(nèi)(通常夠用了)。
weekdayC++20weekday wd(3); 或 wd = Wednesday;構(gòu)造一個(gè)表示星期幾的對(duì)象(0=周日,1=周一...6=周六)。有 Sunday..Saturday 常量。
wd.c_encoding()返回 C 風(fēng)格的編碼(0-6,周日為0)。
wd.iso_encoding()返回 ISO 風(fēng)格的編碼(1-7,周一為1,周日為7)。
wd.ok()檢查是否有效。
last_specC++20last(單例常量)一個(gè)標(biāo)簽類型,用于表示“月份的最后一天”或“最后一個(gè) weekday”。例如 May/last 表示5月31日。

日歷復(fù)合類型

這些類型組合基礎(chǔ)元素,表示更豐富的日期概念。

類型名稱核心接口與表達(dá)式作用與說明
month_daymonth_day md = May/21d;表示“月/日”組合(無年份)。用于描述每年的固定日期,如圣誕節(jié)。
md.ok()檢查是否有效(如 2月30日無效)。
month_day_lastmonth_day_last mdl = May/last;表示某個(gè)月的最后一天(無年份)。
year_monthyear_month ym = 2024y/May;表示“年/月”組合。
ym.ok()檢查年月是否有效。
ym + months(1)加減月份,自動(dòng)處理年份進(jìn)位。
year_month_dayyear_month_day ymd = 2024y/May/21d;最常用的完整日期類型。
ymd.ok()檢查日期是否有效(處理閏年等)。
ymd.year(), ymd.month(), ymd.day()分別獲取年、月、日字段。
sys_days{ymd}轉(zhuǎn)換為 system_clock 的時(shí)間點(diǎn)(基于 days 精度),便于與舊代碼交互。
year_month_day_lastyear_month_day_last ymdl = 2024y/May/last;表示某年某月的最后一天。
ymdl.day()獲取該月的最后一天是幾號(hào)(例如 2024y/February/last 返回 29)。
year_month_weekdayyear_month_weekday ymwd = 2024y/May/Wednesday[3];表示“某年某月的第N個(gè)星期W”,如2024年5月的第三個(gè)星期三。
year_month_weekday_lastyear_month_weekday_last ymwdl = 2024y/May/Wednesday[last];表示“某年某月的最后一個(gè)星期W”。
month_weekdaymonth_weekday mwd = May/Wednesday[3];表示“某月的第N個(gè)星期W”(無年份)。
month_weekday_lastmonth_weekday_last mwdl = May/Wednesday[last];表示“某月的最后一個(gè)星期W”(無年份)。

關(guān)鍵運(yùn)算符與函數(shù)

日歷類型之所以強(qiáng)大,很大程度上歸功于重載的運(yùn)算符。

類別表達(dá)式作用與說明
創(chuàng)建運(yùn)算符/最重要的創(chuàng)建語法。/ 被重載用于組合年、月、日,順序任意,如 2024y/May/21d、21d/May/2024、May/21d/2024 均合法。
算術(shù)運(yùn)算+, -可以對(duì) year_month 加減 months 或 years;對(duì) year_month_day 加減 days、months 或 years。
比較運(yùn)算==, !=, <, <=, >, >=所有日歷類型都支持全系列的比較運(yùn)算符,按日歷順序比較。
差值運(yùn)算-兩個(gè) year_month_day 相減,返回 days 類型的時(shí)長。
流輸出<<大多數(shù)日歷類型都重載了 <<,可以直接 std::cout << ymd;,輸出格式為 YYYY-MM-DD。

代碼示例:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <chrono>
using namespace std::chrono;
using namespace std::literals; // 用于 "y" 和 "d" 字面量
int main() 
{
    // 1. 創(chuàng)建日期的多種方式
    auto ymd1 = 2024y / May / 21d;          // 最直觀
    auto ymd2 = 21d / May / 2024;           // 順序可調(diào)
    auto ymd3 = year_month_day{ 2024y, May, 21d }; // 顯式構(gòu)造

    std::cout << "ymd1 = " << ymd1 << "\n"; // 輸出: 2024-05-21
    std::cout << "ymd2 = " << ymd2 << "\n";
    std::cout << "ymd3 = " << ymd3 << "\n";

    // 2. 訪問日期字段
    std::cout << "年份: " << ymd1.year() << "\n";
    std::cout << "月份: " << ymd1.month() << "\n";
    std::cout << "日: " << ymd1.day() << "\n";

    // 3. 日期算術(shù)
    auto ymd_next_month = ymd1 + months(1);
    std::cout << "下個(gè)月: " << ymd_next_month << "\n"; // 2024-06-21

    auto ymd_next_year = ymd1 + years(1);
    std::cout << "明年: " << ymd_next_year << "\n";     // 2025-05-21

    //將 year_month_day 顯式轉(zhuǎn)換為 sys_days,進(jìn)行天數(shù)算術(shù),再隱式轉(zhuǎn)換回來 
    auto ymd_next_week = year_month_day{ sys_days{ymd1} + days(7) };
    std::cout << "一周后: " << ymd_next_week << "\n";   // 2024-05-28

    // 4. 處理特殊日期:某月最后一天
    auto last_day_of_feb_2024 = 2024y / February / last;
    std::cout << "2024年2月最后一天: " << last_day_of_feb_2024 << "\n"; // 2024-02-29 (閏年)
    std::cout << "那天是星期幾? " << weekday{ last_day_of_feb_2024 } << "\n"; // 轉(zhuǎn)換為 weekday

    // 5. 處理復(fù)雜規(guī)則:某月的第N個(gè)星期W
    auto third_wed_may_2024 = 2024y / May / Wednesday[3];
    std::cout << "2024年5月第三個(gè)星期三: " << third_wed_may_2024 << "\n";

    // 6. 檢查日期有效性
    year_month_day invalid_date = 2024y / February / 30d;
    std::cout << "2024-02-30 有效嗎? " << std::boolalpha << invalid_date.ok() << "\n"; // false

    // 7. 轉(zhuǎn)換為 time_point (用于與 system_clock 交互)
    sys_days tp = sys_days{ ymd1 }; // 轉(zhuǎn)換為基于 days 的時(shí)間點(diǎn)
    std::cout << "時(shí)間點(diǎn) (自紀(jì)元天數(shù)): " << tp.time_since_epoch().count() << " 天\n";

    // 8. 兩個(gè)日期相減得到天數(shù)間隔
    auto xmas = 2024y / December / 25d;
    auto days_until_xmas = sys_days{ xmas } - sys_days{ ymd1 };
    std::cout << "距離2024年圣誕節(jié)還有: " << days_until_xmas.count() << " 天\n";

    // 9. 使用 weekday 計(jì)算下一個(gè)周五
    weekday today = weekday{ ymd1 }; // 2024-05-21 是星期二
    weekday fri = Friday;
    auto days_until_fri = (fri - today).count(); // weekday 差值
    if (days_until_fri <= 0) days_until_fri += 7;
    std::cout << "下一個(gè)周五在 " << days_until_fri << " 天后\n";

    return 0;
}

結(jié)果為:

函數(shù)

時(shí)長(Duration)操作函數(shù)

這些函數(shù)用于操作 duration 對(duì)象,進(jìn)行轉(zhuǎn)換、取整和算術(shù)運(yùn)算。

函數(shù)表達(dá)式引入標(biāo)準(zhǔn)簡要說明
duration_cast<ToDuration>(d)C++11將時(shí)長 d 轉(zhuǎn)換為其他單位,截?cái)嗳≌ㄏ蛄悖?/td>
floor<ToDuration>(d)C++17將時(shí)長 d 向下取整(負(fù)無窮方向)到目標(biāo)單位。
ceil<ToDuration>(d)C++17將時(shí)長 d 向上取整(正無窮方向)到目標(biāo)單位。
round<ToDuration>(d)C++17將時(shí)長 d 四舍五入到目標(biāo)單位,中間情況向偶數(shù)舍入。
abs(d)C++17返回時(shí)長 d 的絕對(duì)值。
d1 + d2, d1 - d2C++11時(shí)長之間的加減法。
d * n, n * d, d / nC++11時(shí)長與標(biāo)量的乘除法。
d1 == d2, d1 < d2, 等C++11時(shí)長之間的比較運(yùn)算符。

時(shí)間點(diǎn)(Time Point)操作函數(shù)

這些函數(shù)用于操作 time_point 對(duì)象,進(jìn)行算術(shù)、轉(zhuǎn)換和取整。

函數(shù)表達(dá)式引入標(biāo)準(zhǔn)簡要說明
time_point_cast<ToDuration>(tp)C++11將時(shí)間點(diǎn) tp 的內(nèi)部時(shí)長單位轉(zhuǎn)換為另一種 duration(截?cái)啵?/td>
floor<ToDuration>(tp)C++17將時(shí)間點(diǎn) tp 向下取整到指定的時(shí)長精度。
ceil<ToDuration>(tp)C++17將時(shí)間點(diǎn) tp 向上取整到指定的時(shí)長精度。
round<ToDuration>(tp)C++17將時(shí)間點(diǎn) tp 四舍五入到指定的時(shí)長精度。
tp + d, tp - dC++11時(shí)間點(diǎn)與時(shí)長相加/減,得到新的時(shí)間點(diǎn)。
tp1 - tp2C++11兩個(gè)時(shí)間點(diǎn)相減,得到 duration 間隔。
tp1 == tp2, tp1 < tp2, 等C++11時(shí)間點(diǎn)之間的比較運(yùn)算符。
clock_cast<DestClock>(tp)C++20將時(shí)間點(diǎn)在不同時(shí)鐘(如 system_clock、utc_clock)之間轉(zhuǎn)換。

日歷(Calendar)操作函數(shù)

C++20引入,用于操作日期類型,提供算術(shù)和比較功能。每個(gè)主要類型都有一組對(duì)應(yīng)的運(yùn)算符。

函數(shù)表達(dá)式類別涉及類型示例簡要說明
算術(shù)運(yùn)算day + days, month + months, year + years, year_month + months, year_month_day + years/months, 等對(duì)日歷類型進(jìn)行加減運(yùn)算,自動(dòng)處理進(jìn)位(如月份加1跨年)。
比較運(yùn)算day == day, month != month, year < year, year_month_day <= year_month_day, 等所有日歷類型都支持完整的比較運(yùn)算符。
差值運(yùn)算year_month_day - year_month_day返回 days 類型,表示兩個(gè)日期的天數(shù)差。
創(chuàng)建語法year/month/day, day/month/year, month/day/year重載的 / 運(yùn)算符,用于直觀地創(chuàng)建日期組合。

輸入/輸出(I/O)函數(shù)

這些函數(shù)用于將 <chrono 類型格式化輸出到流,或從流解析。

函數(shù)表達(dá)式引入標(biāo)準(zhǔn)簡要說明
operator<<(os, duration)C++11輸出時(shí)長(如 "5s")。
operator<<(os, sys_time), operator<<(os, utc_time), 等C++20輸出各種時(shí)鐘的時(shí)間點(diǎn)。
operator<<(os, day), operator<<(os, month), operator<<(os, year), operator<<(os, year_month_day), 等C++20輸出所有日歷類型。
operator<<(os, hh_mm_ss)C++20輸出時(shí)刻(如 "12:30:45.123")。
operator<<(os, sys_info), operator<<(os, local_info)C++20輸出時(shí)區(qū)信息。
from_stream(is, fmt, day), from_stream(is, fmt, year_month_day), 等C++20從輸入流按照指定格式解析日歷類型。
parse(fmt, tp)C++20返回一個(gè)用于解析的占位符,常與 from_stream 配合。

字面量(Literals)運(yùn)算符

定義在內(nèi)聯(lián)命名空間 std::literals::chrono_literals 中,用于便捷書寫時(shí)長和年份。

字面量運(yùn)算符引入標(biāo)準(zhǔn)返回類型/說明
operator""hC++14返回 hours(小時(shí)時(shí)長)
operator""minC++14返回 minutes(分鐘時(shí)長)
operator""sC++14返回 seconds(秒時(shí)長)
operator""msC++14返回 milliseconds(毫秒時(shí)長)
operator""usC++14返回 microseconds(微秒時(shí)長)
operator""nsC++14返回 nanoseconds(納秒時(shí)長)
operator""yC++20返回 year(年份)

測試

日期計(jì)算

以下代碼需要C++20才能編譯通過

Date.h

#define _CRT_SECURE_NO_WARNINGS
#include <chrono>
#include <iostream>
#include <string>
#include< cassert >
class Date {
private:
    std::chrono::year_month_day ymd_;

public:
    // 1. 構(gòu)造函數(shù)
    // 從 std::chrono::year_month_day 構(gòu)造(隱式轉(zhuǎn)換允許)
    Date(const std::chrono::year_month_day& ymd) : ymd_(ymd) {
        if (!ymd_.ok()) {
            throw std::invalid_argument("Invalid date");
        }
    }

    // 從年、月、日整數(shù)構(gòu)造
    Date(int year, int month, int day)
        : Date(std::chrono::year{ year } / month / day) {
    }

    // 2. 靜態(tài)工廠:獲取當(dāng)前日期
    static Date today() {
        auto now = std::chrono::system_clock::now();
        auto today_days = std::chrono::floor<std::chrono::days>(now);
        return Date{ std::chrono::year_month_day{today_days} };
    }

    // 3. 訪問器
    int year() const { return static_cast<int>(ymd_.year()); }
    unsigned month() const { return static_cast<unsigned>(ymd_.month()); }
    unsigned day() const { return static_cast<unsigned>(ymd_.day()); }

    // 獲取星期幾 (Sunday = 0, Monday = 1, ..., Saturday = 6)
    unsigned weekday() const {
        std::chrono::weekday wd{ std::chrono::sys_days{ymd_} };
        return wd.c_encoding(); // 返回 0-6
    }

    // 判斷是否為閏年
    bool isLeapYear() const { return ymd_.year().is_leap(); }

    // 4. 日期算術(shù)運(yùn)算符
    // 加天數(shù)
    Date operator+(const std::chrono::days& d) const {
        auto sd = std::chrono::sys_days{ ymd_ } + d;
        return Date{ std::chrono::year_month_day{sd} };
    }

    // 減天數(shù)
    Date operator-(const std::chrono::days& d) const {
        return *this + (-d);
    }

    // 加月份
    Date operator+(const std::chrono::months& m) const {
        auto new_ymd = ymd_ + m;
        // 處理可能的無效日期(如 1月31日 + 1個(gè)月 = 2月31日,會(huì)調(diào)整到2月最后一天)
        if (!new_ymd.ok()) {
            new_ymd = new_ymd.year() / new_ymd.month() / std::chrono::last;
        }
        return Date{ new_ymd };
    }

    // 減月份
    Date operator-(const std::chrono::months& m) const {
        return *this + (-m);
    }

    // 加年份
    Date operator+(const std::chrono::years& y) const {
        auto new_ymd = ymd_ + y;
        // 處理閏年2月29日的情況
        if (!new_ymd.ok()) {
            new_ymd = new_ymd.year() / new_ymd.month() / std::chrono::last;
        }
        return Date{ new_ymd };
    }

    // 減年份
    Date operator-(const std::chrono::years& y) const {
        return *this + (-y);
    }

    // 復(fù)合賦值運(yùn)算符(可選)
    Date& operator+=(const std::chrono::days& d) { return *this = *this + d; }
    Date& operator-=(const std::chrono::days& d) { return *this = *this - d; }
    Date& operator+=(const std::chrono::months& m) { return *this = *this + m; }
    Date& operator-=(const std::chrono::months& m) { return *this = *this - m; }
    Date& operator+=(const std::chrono::years& y) { return *this = *this + y; }
    Date& operator-=(const std::chrono::years& y) { return *this = *this - y; }

    // 5. 比較運(yùn)算符(C++20 可以自動(dòng)生成,但為清晰顯式聲明)
    auto operator<=>(const Date&) const = default; // C++20 三路比較,自動(dòng)生成所有關(guān)系運(yùn)算符

    // 6. 差值計(jì)算
    // 返回兩個(gè)日期相差的天數(shù)(忽略時(shí)間部分)
    std::chrono::days daysUntil(const Date& other) const {
        return std::chrono::sys_days{ other.ymd_ } - std::chrono::sys_days{ ymd_ };
    }

    // 返回兩個(gè)日期相差的完整月份數(shù)(近似,基于日歷月)
    // 注意:這不是一個(gè)精確的物理時(shí)間差,而是日歷上的月份差。
    int monthsUntil(const Date& other) const {
        // 簡化實(shí)現(xiàn):將年份差 * 12 + 月份差,再根據(jù)日進(jìn)行調(diào)整
        int y1 = year(), m1 = month(), d1 = day();
        int y2 = other.year(), m2 = other.month(), d2 = other.day();

        int month_diff = (y2 - y1) * 12 + (m2 - m1);
        // 如果結(jié)束日期的日號(hào)小于開始日期的日號(hào),則不滿整月
        if (d2 < d1) {
            --month_diff;
        }
        return month_diff;
    }

    // 7. 友元輸出運(yùn)算符
    friend std::ostream& operator<<(std::ostream& os, const Date& date) {
        os << date.year() << '-'
            << (date.month() < 10 ? "0" : "") << date.month() << '-'
            << (date.day() < 10 ? "0" : "") << date.day();
        return os;
    }

    // 獲取內(nèi)部 year_month_day 的引用(用于需要直接操作底層類型的場景)
    const std::chrono::year_month_day& get_ymd() const { return ymd_; }
};

DateTest.cpp

#define _CRT_SECURE_NO_WARNINGS
#include"Date.h"
using namespace std::chrono_literals; // 用于 h, min, s, ms, us, ns, y
void testDate() 
{
    std::cout << "=== 開始測試 Date 類 ===\n";
    // 1. 構(gòu)造函數(shù)與 today()
    std::cout << "1. 構(gòu)造函數(shù)測試:\n";
    Date d1(2024, 5, 21);
    std::cout << "   d1: " << d1 << "\n";
    assert(d1.year() == 2024 && d1.month() == 5 && d1.day() == 21);
    auto d_today = Date::today();
    std::cout << "   Today: " << d_today << "\n";
    // 2. 無效日期拋出異常
    std::cout << "2. 無效日期測試 (2024-02-30): ";
    try {
        Date invalid(2024, 2, 30);
        std::cout << "FAILED: 未拋出異常\n";
    }
    catch (const std::invalid_argument& e) {
        std::cout << "PASSED: 捕獲異常 - " << e.what() << "\n";
    }
    catch (...) {
        std::cout << "FAILED: 捕獲到未知異常\n";
    }
    // 3. 閏年判斷
    std::cout << "3. 閏年判斷測試:\n";
    assert(Date(2024, 1, 1).isLeapYear() == true);
    assert(Date(2023, 1, 1).isLeapYear() == false);
    assert(Date(2000, 1, 1).isLeapYear() == true);
    assert(Date(1900, 1, 1).isLeapYear() == false);
    std::cout << "   所有閏年判斷通過\n";
    // 4. 星期幾
    std::cout << "4. 星期幾測試:\n";
    // 2024-05-21 是星期二 (ISO: 2, C: 2? 需要查證,我們的weekday返回c_encoding)
    // 根據(jù)常識(shí),2024-05-21 是星期二,在weekday中周二對(duì)應(yīng)1(如果周日是0,周一是1,周二是2)
    // 但c_encoding() 周日=0,周一=1,周二=2,周三=3,周四=4,周五=5,周六=6
    assert(Date(2024, 5, 21).weekday() == 2); // 星期二
    assert(Date(2024, 5, 22).weekday() == 3); // 星期三
    assert(Date(2024, 5, 19).weekday() == 0); // 星期日
    std::cout << "   所有星期幾判斷通過\n";
    // 5. 日期算術(shù)
    std::cout << "5. 日期算術(shù)測試:\n";
    Date d2(2024, 5, 21);
    auto d_plus_7 = d2 + std::chrono::days(7);
    std::cout << "   " << d2 << " + 7 days = " << d_plus_7 << "\n";
    assert(d_plus_7 == Date(2024, 5, 28));
    auto d_plus_1m = d2 + std::chrono::months(1);
    std::cout << "   " << d2 << " + 1 month = " << d_plus_1m << "\n";
    assert(d_plus_1m == Date(2024, 6, 21));
    auto d_plus_1y = d2 + std::chrono::years(1);
    std::cout << "   " << d2 << " + 1 year = " << d_plus_1y << "\n";
    assert(d_plus_1y == Date(2025, 5, 21));
    // 邊界測試:月末
    Date d3(2024, 1, 31);
    auto d_plus_1m_jan = d3 + std::chrono::months(1);
    std::cout << "   " << d3 << " + 1 month = " << d_plus_1m_jan << "\n";
    assert(d_plus_1m_jan == Date(2024, 2, 29)); // 2024是閏年,所以是2月29日
    Date d4(2023, 1, 31);
    auto d_plus_1m_jan_nonleap = d4 + std::chrono::months(1);
    std::cout << "   " << d4 << " + 1 month = " << d_plus_1m_jan_nonleap << "\n";
    assert(d_plus_1m_jan_nonleap == Date(2023, 2, 28)); // 2023非閏年,2月28日
    // 跨年測試
    Date d5(2024, 12, 15);
    auto d_plus_2m = d5 + std::chrono::months(2);
    std::cout << "   " << d5 << " + 2 months = " << d_plus_2m << "\n";
    assert(d_plus_2m == Date(2025, 2, 15));
    // 6. 比較運(yùn)算符
    std::cout << "6. 比較運(yùn)算符測試:\n";
    Date d6a(2024, 5, 21);
    Date d6b(2024, 5, 22);
    Date d6c(2024, 5, 21);
    assert(d6a == d6c);
    assert(d6a != d6b);
    assert(d6a < d6b);
    assert(d6a <= d6c);
    assert(d6b > d6a);
    assert(d6b >= d6c);
    std::cout << "   所有比較運(yùn)算符通過\n";
    // 7. 差值計(jì)算
    std::cout << "7. 差值計(jì)算測試:\n";
    Date d7_start(2024, 5, 21);
    Date d7_end(2024, 12, 25);
    auto days_diff = d7_start.daysUntil(d7_end);
    std::cout << "   " << d7_start << " 到 " << d7_end << " 相差 "
        << days_diff.count() << " 天\n";
    assert(days_diff.count() == 218); // 手工驗(yàn)證 5月剩余10天 + 6月30 + 7月31 + 8月31 + 9月30 + 10月31 + 11月30 + 12月25 = 218
    auto months_diff = d7_start.monthsUntil(d7_end);
    std::cout << "   " << d7_start << " 到 " << d7_end << " 相差 "
        << months_diff << " 個(gè)整月\n";
    assert(months_diff == 7); // 5月21日到12月21日是7個(gè)月,到12月25日超過21日,所以仍是7個(gè)整月
    // 跨年差值
    Date d7_start2(2024, 12, 25);
    Date d7_end2(2025, 1, 10);
    auto days_diff2 = d7_start2.daysUntil(d7_end2);
    std::cout << "   " << d7_start2 << " 到 " << d7_end2 << " 相差 "
        << days_diff2.count() << " 天\n";
    assert(days_diff2.count() == 16); // 12月剩余7天 + 1月10天 = 16
    // 8. 復(fù)合賦值
    std::cout << "8. 復(fù)合賦值測試:\n";
    Date d8(2024, 5, 21);
    d8 += std::chrono::days(10);
    std::cout << "   +=10天: " << d8 << "\n";
    assert(d8 == Date(2024, 5, 31));
    d8 += std::chrono::months(1);
    std::cout << "   +=1月: " << d8 << "\n";
    assert(d8 == Date(2024, 6, 30)); // 5月31日+1月 -> 6月30日
    d8 -= std::chrono::years(1);
    std::cout << "   -=1年: " << d8 << "\n";
    assert(d8 == Date(2023, 6, 30));
    std::cout << "=== 所有測試通過 ===\n";
}
int main() 
{
    testDate();
    return 0;
}

結(jié)果為:

性能測試

本期我們以內(nèi)存池為例,對(duì)比其與直接向系統(tǒng)new/delete的性能差距

MemoryPool.h

#define _CRT_SECURE_NO_WARNINGS
#pragma once 
#include <vector>
#include <cassert>
#include <iostream>
using std::vector;
using std::cout;
using std::endl;
namespace MyMemoryPool
{
    // 內(nèi)存對(duì)齊:向上取整到指定對(duì)齊值(align 必須是 2 的冪)
    constexpr inline size_t align_up(size_t n, size_t align)
    {
        return (n + (align - 1)) & ~(align - 1);
    }
    // 固定大小內(nèi)存池,每個(gè)塊大小相同,按頁管理
    class FixedSizePool
    {
    public:
        // 構(gòu)造函數(shù):指定塊大小和每頁塊數(shù)(默認(rèn)1024)
        explicit FixedSizePool(size_t blockSize, size_t blockPerPage = 1024)
            : block_Size(adjust_block_size(blockSize)),   // 確保塊至少能存一個(gè)指針并正確對(duì)齊
            block_Per_Page(blockPerPage),
            free_list(nullptr),
            total_allocations(0),
            total_deallocations(0),
            page_count(0)
        {
        }
        // 析構(gòu)函數(shù):釋放所有已分配的頁
        ~FixedSizePool()
        {
            for (void* page : Pages)
            {
                ::operator delete[](page);   // 全局釋放,避免調(diào)用析構(gòu)函數(shù)
            }
        }
        // 分配一個(gè)塊
        void* allocate()
        {
            if (!free_list)                  // 空閑鏈表為空,需要擴(kuò)充新頁
            {
                expand();
            }
            Node* head = free_list;
            free_list = head->next;
            ++total_allocations;
            return head;
        }
        // 回收一個(gè)塊
        void deallocate(void* p)
        {
            if (!p) return;
            Node* node = static_cast<Node*>(p);
            node->next = free_list;
            free_list = node;
            ++total_deallocations;
        }
        // 獲取塊大小
        size_t Get_block_Size() const { return block_Size; }
        size_t Get_block_Per_Page() const { return block_Per_Page; }
        // 打印統(tǒng)計(jì)信息
        void print_stats() const
        {
            std::cout << "內(nèi)存池統(tǒng)計(jì):" << std::endl;
            std::cout << "  總分配次數(shù): " << total_allocations << std::endl;
            std::cout << "  總釋放次數(shù): " << total_deallocations << std::endl;
            std::cout << "  當(dāng)前使用中: " << (total_allocations - total_deallocations) << std::endl;
            std::cout << "  頁數(shù)量: " << page_count << std::endl;
            std::cout << "  內(nèi)存使用量: " << (page_count * block_Size * block_Per_Page) << " 字節(jié)" << std::endl;
        }
    private:
        // 結(jié)點(diǎn)結(jié)構(gòu),用于空閑鏈表
        struct Node
        {
            Node* next;
        };
        // 申請(qǐng)新的一頁內(nèi)存,并將其切分為多個(gè)塊鏈入空閑鏈表
        void expand()
        {
            size_t page_bytes = block_Size * block_Per_Page;
            char* page = static_cast<char*>(::operator new[](page_bytes));
            Pages.push_back(page);
            ++page_count;
            // 將當(dāng)前頁的所有塊串聯(lián)成鏈表
            for (size_t i = 0; i < block_Per_Page; ++i)
            {
                char* block = page + i * block_Size;
                Node* n = reinterpret_cast<Node*>(block);
                n->next = free_list;
                free_list = n;
            }
        }
        // 調(diào)整塊大?。捍_保至少 sizeof(void*) 并正確對(duì)齊
        size_t adjust_block_size(size_t s) const
        {
            size_t min_size = sizeof(void*);
            return align_up(s < min_size ? min_size : s, alignof(void*));
        }
        Node* free_list;               // 空閑鏈表頭
        size_t block_Size;              // 實(shí)際塊大小(已調(diào)整)
        size_t block_Per_Page;           // 每頁塊數(shù)
        vector<void*> Pages;             // 記錄所有分配過的頁,用于析構(gòu)時(shí)釋放
        // 統(tǒng)計(jì)變量
        size_t total_allocations;
        size_t total_deallocations;
        size_t page_count;
    };
}

MPTest.cpp

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <chrono>
#include <vector>
#include "MemoryPool.h"
using namespace MyMemoryPool;
using namespace std::chrono;
// 通用測試模板:執(zhí)行 iterations 次分配和釋放,返回耗時(shí)(秒)
template <typename AllocFunc, typename DeallocFunc>
double run_test(size_t iterations, AllocFunc alloc, DeallocFunc dealloc) {
    std::vector<void*> pointers;
    pointers.reserve(iterations);
    auto start = high_resolution_clock::now();
    for (size_t i = 0; i < iterations; ++i) {
        pointers.emplace_back(alloc());
    }
    for (void* p : pointers) {
        dealloc(p);
    }
    auto end = high_resolution_clock::now();
    duration<double> elapsed = end - start;
    return elapsed.count();
}
int main() {
    const size_t BLOCK_SIZE = 256;          // 每個(gè)塊 256 字節(jié)
    const size_t BLOCKS_PER_PAGE = 1024;   // 每頁 1024 塊
    const size_t ITERATIONS = 1000000;      // 分配/釋放 100 萬次
    std::cout << "===== 性能對(duì)比測試 =====\n";
    std::cout << "塊大小: " << BLOCK_SIZE << " 字節(jié)\n";
    std::cout << "每頁塊數(shù): " << BLOCKS_PER_PAGE << "\n";
    std::cout << "分配/釋放次數(shù): " << ITERATIONS << "\n\n";
    // 1. 內(nèi)存池測試
    {
        FixedSizePool pool(BLOCK_SIZE, BLOCKS_PER_PAGE);
        double pool_time = run_test(ITERATIONS,
            [&pool]() { return pool.allocate(); },
            [&pool](void* p) { pool.deallocate(p); }
        );
        std::cout << "內(nèi)存池耗時(shí): " << pool_time << " 秒\n";
        pool.print_stats();
    }
    std::cout << "\n";
    // 2. 直接 new/delete 測試
    {
        double new_time = run_test(ITERATIONS,
            []() { return ::operator new(BLOCK_SIZE); },
            [](void* p) { ::operator delete(p); }
        );
        std::cout << "new/delete 耗時(shí): " << new_time << " 秒\n";
    }
    return 0;
}

結(jié)果為:

本期關(guān)于C++中<chrono>庫的介紹就到這里了。熟練運(yùn)用它可以在時(shí)間計(jì)算、性能測試燈多方面領(lǐng)域大展身手!更多相關(guān)C++高精度時(shí)間庫chrono內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++實(shí)現(xiàn)通訊錄功能

    C++實(shí)現(xiàn)通訊錄功能

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)通訊錄功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • C++實(shí)現(xiàn)將內(nèi)容寫入文件的方法總結(jié)

    C++實(shí)現(xiàn)將內(nèi)容寫入文件的方法總結(jié)

    本文主要總結(jié)了一下C/C++將內(nèi)容寫入文件的方法,C的方法有些單調(diào),畢竟沒有庫函數(shù)。C++則豐富些,下面我把搜集到的整理一下,供大家參考
    2023-04-04
  • OpenGL中點(diǎn)Bresenham繪制直線算法

    OpenGL中點(diǎn)Bresenham繪制直線算法

    這篇文章主要為大家詳細(xì)介紹了OpenGL中點(diǎn)Bresenham繪制直線算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • c++中臨時(shí)變量不能作為非const的引用參數(shù)的方法

    c++中臨時(shí)變量不能作為非const的引用參數(shù)的方法

    下面小編就為大家?guī)硪黄猚++中臨時(shí)變量不能作為非const的引用參數(shù)的方法。小編覺得挺不錯(cuò)的現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-01-01
  • 詳解C語言初階基礎(chǔ)(2)

    詳解C語言初階基礎(chǔ)(2)

    這篇文章主要介紹了C語言中的初階基礎(chǔ),介紹了其相關(guān)概念,具有一定參考價(jià)值。需要的朋友可以了解下,希望能夠給你帶來幫助
    2021-11-11
  • C++ 實(shí)現(xiàn)稀疏矩陣的壓縮存儲(chǔ)的實(shí)例

    C++ 實(shí)現(xiàn)稀疏矩陣的壓縮存儲(chǔ)的實(shí)例

    這篇文章主要介紹了C++ 實(shí)現(xiàn)稀疏矩陣的壓縮存儲(chǔ)的實(shí)例的相關(guān)資料,M*N的矩陣,矩陣中有效值的個(gè)數(shù)遠(yuǎn)小于無效值的個(gè)數(shù),且這些數(shù)據(jù)的分布沒有規(guī)律,需要的朋友可以參考下
    2017-07-07
  • C語言詳解鏈?zhǔn)疥?duì)列與循環(huán)隊(duì)列的實(shí)現(xiàn)

    C語言詳解鏈?zhǔn)疥?duì)列與循環(huán)隊(duì)列的實(shí)現(xiàn)

    隊(duì)列(Queue)與棧一樣,是一種線性存儲(chǔ)結(jié)構(gòu),它具有如下特點(diǎn):隊(duì)列中的數(shù)據(jù)元素遵循“先進(jìn)先出”(First In First Out)的原則,簡稱FIFO結(jié)構(gòu)。在隊(duì)尾添加元素,在隊(duì)頭刪除元素,本篇來講解鏈?zhǔn)疥?duì)列與循環(huán)隊(duì)列的實(shí)現(xiàn)
    2022-04-04
  • do...while(0)的妙用詳細(xì)解析

    do...while(0)的妙用詳細(xì)解析

    do...while(0)消除goto語句;通常,如果在一個(gè)函數(shù)中開始要分配一些資源,然后在中途執(zhí)行過程中如果遇到錯(cuò)誤則退出函數(shù),當(dāng)然,退出前先釋放資源
    2013-09-09
  • C++深入探究類與對(duì)象之友元與運(yùn)算符重載

    C++深入探究類與對(duì)象之友元與運(yùn)算符重載

    友元就是讓一個(gè)函數(shù)或者類,訪問另一個(gè)類中的私有成員;打個(gè)比方,這相當(dāng)于是說:朋友是值得信任的,所以可以對(duì)他們公開一些自己的隱私,運(yùn)算符重載的實(shí)質(zhì)就是函數(shù)重載或函數(shù)多態(tài),運(yùn)算符重載是一種形式的C++多態(tài),目的在于讓人能夠用同名的函數(shù)來完成不同的基本操作
    2022-04-04
  • 淺談C++模板元編程

    淺談C++模板元編程

    本篇文章主要介紹了淺談C++模板元編程,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-12-12

最新評(píng)論

灵璧县| 齐河县| 云安县| 正阳县| 高要市| 山阴县| 吉水县| 高州市| 华坪县| 沂源县| 宾川县| 且末县| 保德县| 弥渡县| 昌都县| 西畴县| 禹城市| 勃利县| 广灵县| 西乌珠穆沁旗| 清水河县| 汉中市| 紫阳县| 通州市| 桐乡市| 敦化市| 张家港市| 宜兴市| 阿尔山市| 增城市| 瓦房店市| 潼南县| 庆阳市| 普安县| 化州市| 孟村| 封开县| 隆林| 安龙县| 喀什市| 乐安县|