<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          C++ 日期和時(shí)間編程

          共 14660字,需瀏覽 30分鐘

           ·

          2021-10-30 15:02

          日期和時(shí)間是編程中非常常用的功能。本文是對(duì)C++11到C++17中相關(guān)編程接口的介紹。

          介紹

          C++中可以使用的日期時(shí)間API主要分為兩類:

          • C-style 日期時(shí)間庫(kù),位于<ctime>頭文件中。這是原先<time.h>頭文件的C++版本。
          • chrono庫(kù):C++ 11中新增API,增加了時(shí)間點(diǎn),時(shí)長(zhǎng)和時(shí)鐘等相關(guān)接口。

          在C++11之前,C++編程只能使用C-style日期時(shí)間庫(kù)。其精度只有秒級(jí)別,這對(duì)于有高精度要求的程序來(lái)說(shuō),是不夠的。

          但這個(gè)問(wèn)題在C++11中得到了解決,C++11中不僅擴(kuò)展了對(duì)于精度的要求,也為不同系統(tǒng)的時(shí)間要求提供了支持。

          另一方面,對(duì)于只能使用C-style日期時(shí)間庫(kù)的程序來(lái)說(shuō),C++17中也增加了timespec將精度提升到了納秒級(jí)別。

          代碼示例

          本文中所貼出的代碼示例可以到我的Github上獲?。?span style="outline: 0px;color: rgb(30, 107, 184);font-weight: bold;">paulQuei/cpp-date-time[1]

          或者,你也可以直接通過(guò)下面這條命令獲取所有源碼:

          git clone https://github.com/paulQuei/cpp-date-time.git

          為了簡(jiǎn)化書(shū)寫(xiě),本文中給出的代碼都已經(jīng)默認(rèn)做了以下操作:

          #include <chrono>
          #include <ctime>
          #include <iostream>

          using namespace std;

          C-style 日期時(shí)間庫(kù)

          C-style 日期時(shí)間庫(kù)中包含的函數(shù)和數(shù)據(jù)類型說(shuō)明如下:

          函數(shù)

          函數(shù)說(shuō)明
          std::clock_t clock()返回自程序啟動(dòng)時(shí)起的處理器時(shí)鐘時(shí)間
          std::time_t time(std::time_t* arg)返回自紀(jì)元起計(jì)的系統(tǒng)當(dāng)前時(shí)間
          double difftime(std::time_t time_end,   std::time_t time_beg)計(jì)算時(shí)間之間的差
          int timespec_get(std::timespec* ts, int base)??返回基于給定時(shí)間基底的日歷時(shí)間
          char* ctime(const std::time_t* time)轉(zhuǎn)換 time_t 對(duì)象為文本表示
          char* asctime(const std::tm* time_ptr)轉(zhuǎn)換 tm 對(duì)象為文本表示
          std::size_t strftime(char* str,   std::size_t count, const char* format,   const std::tm* time)轉(zhuǎn)換 tm 對(duì)象到自定義的文本表示
          std::size_t wcsftime( wchar_t* str,   std::size_t count, const wchar_t* format,   const std::tm* time)轉(zhuǎn)換 tm 對(duì)象為定制的寬字符串文本表示
          std::tm* gmtime(const std::time_t* time)將time_t轉(zhuǎn)換成UTC表示的時(shí)間
          std::tm* localtime(const std::time_t *time)將time_t轉(zhuǎn)換成本地時(shí)間
          std::time_t mktime(std::tm* time)將tm格式的時(shí)間轉(zhuǎn)換成time_t表示的時(shí)間

          數(shù)據(jù)類型

          名稱說(shuō)明
          time_t從紀(jì)元起的時(shí)間類型
          tm日歷時(shí)間類型
          timespec??以秒和納秒表示的時(shí)間
          clock_t進(jìn)程運(yùn)行時(shí)間
          size_tsizeof 運(yùn)算符返回的無(wú)符號(hào)整數(shù)類型

          結(jié)構(gòu)梳理

          這里有不少的函數(shù)和數(shù)據(jù)類型,剛開(kāi)始接觸的時(shí)候似乎不太容易記得住。

          但實(shí)際上,如果我們把它們畫(huà)成一張圖就比較好理解了,如下所示:

          img

          在這幅圖中,以數(shù)據(jù)類型為中心,帶方向的實(shí)線箭頭表示該函數(shù)能返回相應(yīng)類型的結(jié)果。

          • clock函數(shù)是相對(duì)獨(dú)立的一個(gè)函數(shù),它返回進(jìn)程運(yùn)行的時(shí)間,具體描述見(jiàn)下文。
          • time_t描述了紀(jì)元時(shí)間,通過(guò)time函數(shù)可以獲得它。但它只能精確到秒級(jí)別。
          • timespec類型在time_t的基礎(chǔ)上,增加了納秒的精度,通過(guò)timespec_get獲取。這是C++17上新增的
          • tm是日歷類型,因?yàn)樗渲邪四暝氯盏刃畔?。通過(guò)gmtime,localtime和mktime函數(shù)可以將time_t和tm類型互相轉(zhuǎn)換。
          • 考慮到時(shí)區(qū)的差異,因此存在gmtime和localtime兩個(gè)函數(shù)。
          • 無(wú)論是time_t還是tm結(jié)構(gòu),都可以將其以字符串格式輸出。ctime和asctime輸出的格式是固定的。如果需要自定義格式,需要使用strftime或者wcsftime函數(shù)。

          進(jìn)程運(yùn)行時(shí)間

          clock函數(shù)返回進(jìn)程迄今為止所用的處理器時(shí)間。單獨(dú)調(diào)度該函數(shù)一次所返回的值是沒(méi)有意義的,只有兩次不同值的差才有意義。

          該值表示了進(jìn)程從關(guān)聯(lián)到程序執(zhí)行的實(shí)現(xiàn)定義時(shí)期開(kāi)始,所用的粗略處理器時(shí)間。而且這個(gè)值僅僅是處理器的時(shí)鐘周期。如果希望將其轉(zhuǎn)換為以秒為單位,還需要將它除以常量 CLOCKS_PER_SEC 。

          下面是一段代碼示例:

          clock_t time1 = clock();
          double sum = 0;
          for(int i = 0; i < 100000000; i++) {
            sum += sqrt(i);
          }
          clock_t time2 = clock();

          double t = ((double)(time2 - time1)) / CLOCKS_PER_SEC ;
          cout << "CLOCKS_PER_SEC: " << CLOCKS_PER_SEC << endl;
          cout << "Process running time: " << t << "s" << endl;

          其輸出如下:

          CLOCKS_PER_SEC: 1000000
          Process running time: 0.80067s

          你可能知道,現(xiàn)代的操作系統(tǒng)上進(jìn)程都是分時(shí)占用處理器的,所以程序的處理器時(shí)間會(huì)小于真實(shí)世界流逝的時(shí)間。但這僅僅是對(duì)于單處理器而言的。在多處理器系統(tǒng)上,如果你的進(jìn)程使用了多線程,那么其所用的處理器時(shí)間可能比真實(shí)世界流逝的時(shí)間值還要大。

          關(guān)于紀(jì)元時(shí)間

          紀(jì)元時(shí)間(Epoch time)又叫做Unix時(shí)間或者POSIX時(shí)間。它表示自1970 年 1 月 1 日 00:00 UTC 以來(lái)所經(jīng)過(guò)的秒數(shù)(不考慮閏秒)。它在操作系統(tǒng)和文件格式中被廣泛使用。

          這個(gè)想法很簡(jiǎn)單:以一個(gè)時(shí)間為起點(diǎn)加上一個(gè)偏移量便可以表達(dá)任何一個(gè)其他的時(shí)間。

          如果你好奇為什么選這個(gè)時(shí)間作為起點(diǎn),可以點(diǎn)擊這里:Why is 1/1/1970 the “epoch time”?[2]

          下面是一個(gè)代碼示例:

          time_t epoch_time = time(nullptr);
          cout << "Epoch time: " << epoch_time << endl;

          其輸出如下:

          Epoch time: 1577433897

          time函數(shù)接受一個(gè)指針,指向要存儲(chǔ)時(shí)間的對(duì)象,通??梢詡鬟f一個(gè)空指針,然后通過(guò)返回值來(lái)接受結(jié)果。

          雖然標(biāo)準(zhǔn)中沒(méi)有給出定義,但time_t通常使用整形值來(lái)實(shí)現(xiàn)。

          作為一個(gè)程序員,你可能馬上會(huì)意識(shí)到整形的位數(shù)和溢出的問(wèn)題。事實(shí)也剛好是這樣,在一些歷史實(shí)現(xiàn)上使用了32位有符號(hào)整數(shù)來(lái)實(shí)現(xiàn)time_t,其造成的結(jié)果就是:在2038-01-19 03:14:07[3]這個(gè)時(shí)間點(diǎn),這個(gè)值會(huì)溢出。

          不過(guò)不用擔(dān)心太多,這個(gè)時(shí)間距現(xiàn)在還有將近20年,到那個(gè)時(shí)候,估計(jì)那些有問(wèn)題的系統(tǒng)已經(jīng)不會(huì)再繼續(xù)運(yùn)轉(zhuǎn)或者已經(jīng)被升級(jí)了。

          計(jì)算時(shí)間差

          在一些情況下,我們需要計(jì)算一個(gè)操作的時(shí)間長(zhǎng)度。這自然的就需要計(jì)算兩個(gè)時(shí)間點(diǎn)的差分。這時(shí)就可以使用difftime函數(shù)。

          事實(shí)上,我們知道time_t以秒級(jí)別表示紀(jì)元時(shí)間,并且它又是以整形實(shí)現(xiàn)的,直接將兩個(gè)time_t相減,可以得到相同的結(jié)果。

          下面是一個(gè)代碼示例:

          time_t time1 = time(nullptr);
          double sum = 0;
          for(int i = 0; i < 1000000000; i++) {
            sum += sqrt(i);
          }
          time_t time2 = time(nullptr);

          double time_diff = difftime(time2, time1);
          cout << "time1: " << time1 << endl;
          cout << "time2: " << time2 << endl;
          cout << "time_diff: " << time_diff << "s" << endl;

          其輸出如下,可以看到這正是time1和time2兩個(gè)整數(shù)相減的結(jié)果:

          time1: 1577434406
          time2: 1577434414
          time_diff: 8s

          注意:time_t只精確到秒,它無(wú)法描述毫秒級(jí)別的時(shí)間,所以在有更高精度要求的情況下,需要使用下文提到的其他方法。

          輸出時(shí)間和日期

          當(dāng)然,我們還希望將時(shí)間以字符串的形式打印出來(lái)。這時(shí)就可以使用ctime函數(shù)。不過(guò)該函數(shù)打印的格式是固定的:Www Mmm dd hh:mm:ss yyyy\n。如果你希望自定義輸出的格式,可以使用下文提到的其他方法。

          下面是一個(gè)代碼示例:

          time_t now = time(nullptr);
          cout << "Now is: " << ctime(&now);

          其輸出如下:

          Now is: Fri Dec 27 16:17:45 2019

          UTC時(shí)間與本地時(shí)間

          對(duì)于一個(gè)具體的時(shí)刻來(lái)說(shuō),不同時(shí)區(qū)的具體時(shí)間是不一樣的,例如:東京時(shí)間就比北京時(shí)間快了一個(gè)小時(shí)。

          我們既有可能需要知道無(wú)差別的標(biāo)準(zhǔn)時(shí)間(UTC時(shí)間),例如:計(jì)算一個(gè)航班的時(shí)長(zhǎng)。也有可能需要獲取某個(gè)當(dāng)?shù)氐木唧w時(shí)間:gmtime用來(lái)將 std::time_t 的紀(jì)元時(shí)間轉(zhuǎn)換為UTC時(shí)間,而localtime則將紀(jì)元時(shí)間轉(zhuǎn)換為本地時(shí)區(qū)所代表的日歷時(shí)間。

          日歷時(shí)間使用tm結(jié)構(gòu)描述。其結(jié)構(gòu)如下:

          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;
          };

          需要注意的是:

          • tm_mon 并非我們?nèi)祟惱斫獾脑路?,而是[0, 11]的范圍。因此在某些時(shí)候你可能要對(duì)其+1.
          • tm_year 是自1900起之年,因此你可能也需要對(duì)其 +1900。

          asctime可以直接將tm結(jié)構(gòu)轉(zhuǎn)換成人類理解的字符串格式,不過(guò)其格式是固定的:Www Mmm dd hh:mm:ss yyyy\n。對(duì)于有特定格式要求,可以使用下文提到的其他方法。

          下面是一個(gè)代碼示例:

          time_t now = time(nullptr);

          tm* gm_time = gmtime(&now);
          tm* local_time = localtime(&now);

          cout << "gmtime: " << asctime(gm_time);
          cout << "local_time: " << asctime(local_time);

          其輸出如下:

          gmtime: Fri Dec 27 08:36:14 2019
          local_time: Fri Dec 27 16:36:14 2019

          由于北京時(shí)間的時(shí)區(qū)是GMT+8,所以我的本地時(shí)間比UTC時(shí)間快8個(gè)小時(shí)。

          自定義時(shí)間格式

          無(wú)論是ctime函數(shù)還是asctime函數(shù),其輸出的格式都是固定的。在有格式要求的情況下,它們并不能完成需求。

          當(dāng)然,你可以直接讀取tm結(jié)構(gòu)體中的字段來(lái)進(jìn)行輸出,例如:

          time_t now = time(nullptr);
          tm* t = localtime(&now);

          cout << "Now is: " << t->tm_year + 1900 << "/" << t->tm_mon + 1<< "/" << t->tm_mday << " ";
          cout << t->tm_hour << ":" << t->tm_min << ":" << t->tm_sec << endl;

          請(qǐng)注意這段代碼中,需要對(duì)tm_year和tm_mon進(jìn)行轉(zhuǎn)換才是我們?nèi)粘@斫獾娜掌凇?/p>

          很顯然,這樣寫(xiě)太啰嗦了。

          更好的方法是:使用strftime或者wcsftime函數(shù)來(lái)指定格式輸出。關(guān)于這兩個(gè)函數(shù)的格式,可以看這個(gè)鏈接:std::strftime format[4]。

          想要輸出上面代碼同樣的格式,只要這樣就可以完成任務(wù)了:

          char buffer[32];
          strftime(buffer, 32, "%Y/%m/%d %H:%M:%S", t);
          cout << "Now is: " << buffer << endl;

          它們會(huì)輸出同樣的結(jié)果:

          Now is: 2019/12/27 16:40:39

          除了<ctime>之外,為了方便時(shí)間的輸入輸出,從C++11開(kāi)始,在<iomanip>頭文件中還增加了put_time[5]get_time[6]兩個(gè)函數(shù)。

          納秒精度的timespec

          前面我們已經(jīng)說(shuō)了,紀(jì)元時(shí)間的精度只有秒級(jí)別。這在很多時(shí)候是不夠用的。

          為了解決這個(gè)問(wèn)題,C++17上增加了timespec類型提供了納秒級(jí)別的精度。

          以下是四個(gè)時(shí)間單位的換算和英文表示:

          1秒(Second)=103毫秒(millisecond)=106微妙(microsecond)=109納秒(nanosecond)(1)(1)1秒(Second)=103毫秒(millisecond)=106微妙(microsecond)=109納秒(nanosecond)

          timespec類型結(jié)構(gòu)如下:

          struct timespec {
            std::time_t tv_sec;
            long tv_nsec;
          };

          可以看到,這里是在time_t之外,增加了一個(gè)tv_nsec來(lái)表達(dá)納秒的數(shù)量。為了獲取這個(gè)值,C++17新增了timespec_get函數(shù)。

          以下是一個(gè)代碼示例:

          timespec ts;
          timespec_get(&ts, TIME_UTC);
          char buff[100];
          strftime(buff, sizeof buff, "%D %T", std::gmtime(&ts.tv_sec));
          printf("Current time: %s.%09ld UTC\n", buff, ts.tv_nsec);

          timespec_get的第二個(gè)參數(shù)是一個(gè)整形表達(dá)的base。目前標(biāo)準(zhǔn)只定義了TIME_UTC。

          其輸出如下:

          Current time: 12/27/19 09:03:29.497456000 UTC

          說(shuō)完了C-style日期時(shí)間庫(kù),讓我們?cè)賮?lái)看看C++11新增的chrono庫(kù)。

          chrono 庫(kù)

          “chrono”是英文chronology的縮寫(xiě),其含義是“年表;年代學(xué)”。

          時(shí)鐘

          為了滿足不同類型的需求,C++11 chrono庫(kù)中包含了三種類型的時(shí)鐘,它們的說(shuō)明如下:

          名稱說(shuō)明
          system_clock系統(tǒng)時(shí)鐘
          steady_clock單調(diào)時(shí)鐘,不會(huì)被調(diào)整
          high_resolution_clock擁有可用的最短嘀嗒周期的時(shí)鐘

          system_clock 的時(shí)間來(lái)源是系統(tǒng)時(shí)鐘,而系統(tǒng)時(shí)間隨時(shí)都可能被調(diào)整。所以如果你需要計(jì)算兩個(gè)時(shí)間點(diǎn)的時(shí)間差,這不是一個(gè)好的選擇。因?yàn)槿绻麅纱螘r(shí)間差中間系統(tǒng)時(shí)間被調(diào)整了,其結(jié)果就沒(méi)有意義了。

          steady_clock會(huì)保證單調(diào)性。它就好像物理時(shí)間只會(huì)向前移動(dòng),無(wú)法減少。它最適合用來(lái)度量間隔。

          high_resolution_clock 表示實(shí)現(xiàn)提供的擁有最小計(jì)次周期的時(shí)鐘。它可以是 system_clock 或 steady_clock 的別名,也可能是第三個(gè)獨(dú)立時(shí)鐘。

          這三個(gè)時(shí)鐘類有一些共同的成員,如下所示:

          名稱說(shuō)明
          now()now()靜態(tài)成員函數(shù),返回當(dāng)前時(shí)間,類型為clock::time_point
          time_point成員類型,當(dāng)前時(shí)鐘的時(shí)間點(diǎn)類型,見(jiàn)下文“時(shí)間點(diǎn)”
          duration成員類型,時(shí)鐘的時(shí)長(zhǎng)類型,見(jiàn)下文“時(shí)長(zhǎng)”
          rep成員類型,時(shí)鐘的tick類型,等同于clock::duration::rep
          period成員類型,時(shí)鐘的單位,等同于clock::duration::period
          is_steady靜態(tài)成員類型:是否是穩(wěn)定時(shí)鐘,對(duì)于steady_clock來(lái)說(shuō)該值一定是true

          每種時(shí)鐘類都有一個(gè) now()now() 靜態(tài)函數(shù)來(lái)獲取當(dāng)前時(shí)間,返回的類型是由該時(shí)鐘類下的time_point描述。這是一個(gè)std::chrono::time_point模板類的具體實(shí)例,例如:std::chrono::time_pointstd::chrono::system_clock或者std::chrono::time_pointstd::chrono::steady_clock。是的,這個(gè)類型太長(zhǎng)了,不過(guò)在C++11中,你可以用auto關(guān)鍵字來(lái)簡(jiǎn)寫(xiě)。

          例如,下面是不使用和使用auto關(guān)鍵字的寫(xiě)法:

          std::chrono::time_point<std::chrono::steady_clock> now = std::chrono::steady_clock::now();

          auto now2 = std::chrono::steady_clock::now();

          與C-style轉(zhuǎn)換

          system_clock與另外兩個(gè)clock不一樣的地方在于,它還提供了兩個(gè)靜態(tài)函數(shù)用來(lái)與std::time_t來(lái)回轉(zhuǎn)換:

          名稱說(shuō)明
          to_time_t轉(zhuǎn)換系統(tǒng)時(shí)鐘時(shí)間點(diǎn)為 std::time_t
          from_time_t轉(zhuǎn)換 std::time_t 到系統(tǒng)時(shí)鐘時(shí)間點(diǎn)

          由此,我們可以通過(guò)下面這幅圖來(lái)描述幾種時(shí)間類型的轉(zhuǎn)換:

          img

          下面是一個(gè)代碼示例:

          auto now = chrono::system_clock::now();
          time_t time = chrono::system_clock::to_time_t(now);
          cout << "Now is: " << ctime(&time) << endl;

          時(shí)長(zhǎng)

          ratio

          人類對(duì)于精度的要求是沒(méi)有止境的。雖然目前的精度已經(jīng)從秒到毫秒,微妙甚至納秒。但很難說(shuō)今后還會(huì)不會(huì)有更高精度的要求。

          前面我們已經(jīng)看到,為了將精度從秒變成納秒,C++17增加了timespec_get函數(shù)和timespec類型。如果以后還有更高的精度要求,C++標(biāo)準(zhǔn)還需要添加更多的函數(shù)和類型嗎?老實(shí)說(shuō),這不是一個(gè)好的設(shè)計(jì)。

          為了解決這個(gè)問(wèn)題,C++11中添加了一個(gè)新的頭文件和類型,那就是:ratio。

          std::ratio描述了編譯時(shí)的有理數(shù),這是一個(gè)模板類。有了這個(gè)類型之后,我們就可以表示任意精度的值了。

          例如:相對(duì)于秒來(lái)說(shuō),毫秒是11,00011,000,微妙是11,000,00011,000,000,納秒是11,000,000,00011,000,000,000。通過(guò)ratio可以這樣表達(dá):

          std::ratio<1, 1000>       milliseconds;
          std::ratio<1, 1000000>    microseconds;
          std::ratio<1, 1000000000> nanoseconds;

          其實(shí)上,<ratio>頭文件中包含了很多以10為基數(shù)的各種分?jǐn)?shù),具體可以見(jiàn)這里:編譯時(shí)有理數(shù)算術(shù)[7]。

          我們只需要通過(guò):std::milli,std::micro,std::nano使用就好了。

          當(dāng)然,ratio能表達(dá)的數(shù)值不僅僅是以10為基底的。對(duì)于任意的分?jǐn)?shù)都可以表達(dá),例如: 5757,591023591023等等。

          對(duì)于一個(gè)具體的ratio來(lái)說(shuō),可以通過(guò)den獲取分母的值,num獲取分子的值。

          不僅僅如此,<ratio>頭文件還包含了:ratio_add,ratio_subtract,ratio_multiply,ratio_divide來(lái)完成分?jǐn)?shù)的加減乘除四則運(yùn)算。

          例如,想要計(jì)算57+59102357+591023,可以這樣寫(xiě):

          ratio_add<ratio<5, 7>, ratio<59, 1023>> result;
          double value = ((double) result.num) / result.den;
          cout << result.num << "/" << result.den << " = " << value << endl;

          請(qǐng)注意:無(wú)論是分子還是分母,都是一個(gè)整形。在C++中,整形的除法結(jié)果仍然是整形,多余部分會(huì)被丟棄,因此想要獲取double類型的結(jié)果,需要先將其轉(zhuǎn)換成double。

          這段代碼輸出的結(jié)果是:

          5528/7161 = 0.771959

          時(shí)長(zhǎng)類型

          類模板 std::chrono::duration 表示時(shí)間間隔。有了ratio之后,表達(dá)時(shí)長(zhǎng)就很方便了,下面是chrono庫(kù)中提供的很常用的幾個(gè)時(shí)長(zhǎng)單位:

          類型定義
          std::chrono::nanosecondsduration</至少 64 位的有符號(hào)整數(shù)類型/, std::nano>
          std::chrono::microsecondsduration</至少 55 位的有符號(hào)整數(shù)類型/, std::micro>
          std::chrono::millisecondsduration</至少 45 位的有符號(hào)整數(shù)類型/, std::milli>
          std::chrono::secondsduration</至少 35 位的有符號(hào)整數(shù)類型/>
          std::chrono::minutesduration</至少 29 位的有符號(hào)整數(shù)類型/, std::ratio<60?
          std::chrono::hoursduration</至少 23 位的有符號(hào)整數(shù)類型/, std::ratio<3600?

          duration類的count()成員函數(shù)返回具體數(shù)值。

          時(shí)長(zhǎng)運(yùn)算

          時(shí)長(zhǎng)之間最常用的運(yùn)算自然是相加或者相減,這個(gè)通過(guò)“+”,“-”就可以完成。

          除此之外,chrono庫(kù)中還提供了下面幾個(gè)常用的函數(shù):

          函數(shù)說(shuō)明
          duration_cast進(jìn)行時(shí)長(zhǎng)的轉(zhuǎn)換
          floor(C++17)以向下取整的方式,將一個(gè)時(shí)長(zhǎng)轉(zhuǎn)換為另一個(gè)時(shí)長(zhǎng)
          ceil(C++17)以向上取整的方式,將一個(gè)時(shí)長(zhǎng)轉(zhuǎn)換為另一個(gè)時(shí)長(zhǎng)
          round(C++17)轉(zhuǎn)換時(shí)長(zhǎng)到另一個(gè)時(shí)長(zhǎng),就近取整,偶數(shù)優(yōu)先
          abs(C++17)獲取時(shí)長(zhǎng)的絕對(duì)值

          例如:想要知道2個(gè)小時(shí)零5分鐘一共是多少秒,可以這樣寫(xiě):

          chrono::hours two_hours(2);
          chrono::minutes five_minutes(5);

          auto duration = two_hours + five_minutes;
          auto seconds = chrono::duration_cast<chrono::seconds>(duration);
          cout << "02:05 is " << seconds.count() << " seconds" << endl;

          我們可以得到:

          02:05 is 7500 seconds

          從C++14開(kāi)始,你甚至可以用字面值來(lái)描述常見(jiàn)的時(shí)長(zhǎng)。這包括:

          • h表示小時(shí)
          • min表示分鐘
          • s表示秒
          • ms表示毫秒
          • us表示微妙
          • ns表示納秒

          這些字面值位于std::chrono_literals命名空間下。于是,可以這樣表達(dá)2個(gè)小時(shí)以及5分鐘:

          using namespace std::chrono_literals;
          auto two_hours = 2h;
          auto five_minutes = 5min;

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

          時(shí)間點(diǎn)中包含了時(shí)鐘和時(shí)長(zhǎng)兩個(gè)信息,類模板 std::chrono::time_point 表示時(shí)間中的一個(gè)點(diǎn)。

          時(shí)鐘的now()now()函數(shù)返回的值就是一個(gè)時(shí)間點(diǎn)。time_point中的time_since_epoch()返回從其時(shí)鐘起點(diǎn)開(kāi)始的時(shí)長(zhǎng)。

          時(shí)間點(diǎn)運(yùn)算

          時(shí)間點(diǎn)有加法操作和減法操作,與我們的常識(shí)相一致:

          時(shí)間點(diǎn) + 時(shí)長(zhǎng) = 時(shí)間點(diǎn)
          時(shí)間點(diǎn) - 時(shí)間點(diǎn) = 時(shí)長(zhǎng)

          例如:可以通過(guò)兩個(gè)時(shí)間點(diǎn)相減計(jì)算一個(gè)時(shí)間間隔,下面是一個(gè)代碼示例:

          auto start = chrono::steady_clock::now();
          double sum = 0;
          for(int i = 0; i < 100000000; i++) {
              sum += sqrt(i);
          }
          auto end = chrono::steady_clock::now();

          auto time_diff = end - start;
          auto duration = chrono::duration_cast<chrono::milliseconds>(time_diff);
          cout << "Operation cost : " << duration.count() << "ms" << endl;

          上面這個(gè)代碼很好的說(shuō)明了:有了duration和duration_cast,我們可以以任意的精度來(lái)描述結(jié)果的值。

          除了相加和相減,兩個(gè)時(shí)間點(diǎn)還有比較操作:判斷一個(gè)時(shí)間點(diǎn)在另外一個(gè)時(shí)間點(diǎn)之前還是之后。對(duì)于這些操作,通過(guò)運(yùn)算符:==,!=,<<=,>>=來(lái)完成。

          展望 C++ 20

          通過(guò)上面的講解我們可以看到,自C++11以來(lái),日期時(shí)間庫(kù)功能獲得了極大的提升。并且,在C++14和C++17上也有一些小改進(jìn)。

          但如果你使用過(guò)Java類庫(kù),就會(huì)覺(jué)得差距還是比較大。Java中的相關(guān)API早就有對(duì)于日歷,時(shí)區(qū)等方面更好的支持。

          對(duì)于這一點(diǎn), 在C++下一個(gè)標(biāo)準(zhǔn)C++20中,將有相應(yīng)的支持。這些改進(jìn)包括:

          • 更多類型的時(shí)鐘,例如:utc_clock,tai_lock,gps_clock等。
          • 時(shí)鐘以及時(shí)間點(diǎn)的轉(zhuǎn)換
          • Calendar支持
          • 時(shí)區(qū)支持

          關(guān)于這一點(diǎn),你可以看這個(gè)鏈接:Date and time utilities[8]。

          如果想獲取更多關(guān)于C++20的信息,可以直接看這里:N4842:《Working Draft, Standard for Programming Language C++》[9]。

          參考資料與推薦讀物

          • cppreference: Date and time utilities[10]
          • cppreference: Standard library header [11]
          • [The C++ Standard Library: A Tutorial and Reference, 2nd Edition](

          參考資料

          [1]

          paulQuei/cpp-date-time: https://github.com/paulQuei/cpp-date-time

          [2]

          Why is 1/1/1970 the “epoch time”?: https://stackoverflow.com/questions/1090869/why-is-1-1-1970-the-epoch-time

          [3]

          2038-01-19 03:14:07: https://en.wikipedia.org/wiki/Year_2038_problem

          [4]

          std::strftime format: https://zh.cppreference.com/w/cpp/chrono/c/strftime

          [5]

          put_time: https://zh.cppreference.com/w/cpp/io/manip/put_time

          [6]

          get_time: https://zh.cppreference.com/w/cpp/io/manip/get_time

          [7]

          編譯時(shí)有理數(shù)算術(shù): https://zh.cppreference.com/w/cpp/numeric/ratio

          [8]

          Date and time utilities: https://en.cppreference.com/w/cpp/chrono

          [9]

          N4842:《Working Draft, Standard for Programming Language C++》: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/n4842.pdf

          [10]

          cppreference: Date and time utilities: https://en.cppreference.com/w/cpp/chrono

          [11]

          cppreference: Standard library header : https://en.cppreference.com/w/cpp/header/ctime

          文章鏈接:https://paul.pub/cpp-date-time/

          瀏覽 43
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲成人精品在线观看 | 日韩人妻一区二区 | 色噜噜亚洲欧美在线视频 | 无码视频豆花视频不卡 | 大香蕉免费福利视频 |