C++14系列(2):C/C++的時間函數

C++筆記開始

爲了好好研究下C++14,順便複習下以前的C++知識。搞了個git(不斷完善中):
https://github.com/rododo/cpp14examples.git
裏面會慢慢封裝一些常用的函數,並做一些測試驗證,工程是建立在Ubuntu的Eclipse之上,見系列(1)環境搭建。

常用的時間函數

參考:
http://blog.chinaunix.net/uid-24517893-id-363870.html

時間函數常用到的幾個概念:Calendar Time(日曆時間),epoch(時間點),clock tick(時鐘計時單元)Coordinated Universal Time(UTC):世界標準時間,即格林威治標準時間(Greenwich Mean Time,GMT)。

epoch:時間點。在標準C/C++中是一個整數,它用當前的時間和標準時間點的相差秒數來表示。它可以理解成日曆時間,因爲它已經是一個差值了。

日曆時間(Calendar Time),是用“從一個標準時間點到此時的時間經過的秒數”來表示的時間。

clock tick:時鐘計時單元,一個時鐘計時單元的時間長短是由CPU控制的。一個clock tick不是CPU的一個時鐘週期,而是C/C++的一個基本計時單位。

進程的CPU使用時間計時

C/C++中的cpu使用計時函數是clock(),而與其相關的數據類型是clock_t。這個函數返回從“開啓這個程序進程”到“程序中調用clock()函數”時之間的CPU時鐘計時單元(clock tick)數,其中clock_t是用來保存時間的數據類型。
clock_t是一個長整形數。在time.h文件中,還定義了一個常量CLOCKS_PER_SEC,它用來表示一秒鐘會有多少個時鐘計時單元,如下打印的是進程運行至今佔用的cpu時間秒數,並且它是算單核的秒數,如果這個程序是多線程的,core1和core2同時被某程序的兩個線程使用了5s的cpu運行時間片,那麼此時打印的應該是10s(已經驗證)。

printf("Elapsed time:%u secs.\n",clock()/CLOCKS_PER_SEC);

日曆時間

在C/C++中通過 < time.h > 裏的time函數獲得日曆時間。日曆時間(Calendar Time)是通過time_t數據類型來表示的,用time_t表示的時間(日曆時間)是從一個時間點(例如:1970年1月1日0時0分0秒)到此時的秒數。time_t實際上是長整型。
用time()函數結合其他函數(如:localtime、gmtime、asctime、ctime)可以獲得當前系統時間或是標準時間。

time_t time(time_t * timer);

日曆時間(秒)與日期(年月日)關係

在標準C/C++中,我們可通過tm結構來獲得日期,tm結構在time.h中有定義,相當於一個包含了年月日小時分鐘等的結構體。

ANSI C標準稱使用tm結構的這種時間表示爲分解時間(broken-down time)。
而日曆時間(Calendar Time)是從一個時間點到此時的秒數,類型比較簡單。

在time.h頭文件中,我們還可以看到一些函數,它們都是以time_t爲參數類型或返回值類型的函數:

double difftime(time_t time1, time_t time0);
time_t mktime(struct tm * timeptr);
time_t time(time_t * timer);
char * asctime(const struct tm * timeptr);
char * ctime(const time_t *timer);

此外,time.h還提供了兩種不同的函數將日曆時間(一個用time_t表示的整數)轉換爲我們平時看到的把年月日時分秒分開顯示的時間格式tm:

struct tm * gmtime(const time_t *timer);                                          
struct tm * localtime(const time_t * timer);

固定的日期格式打印

使用函數:

char * asctime(const struct tm * timeptr);
char * ctime(const time_t *timer);

打印結果:
例如 Wed Jan 02 02:03:55 1980\n\0

其中asctime()函數是通過tm結構來生成字符串,所以可以傳給世界時間或者本地時間,而ctime()是通過日曆時間來生成字符串。ctime()函數需要先參照本地的時間設置,把日曆時間轉化爲本地時間,然後再生成格式化後的字符串。所以一般其打印的是本地時間字符串。

自定義的日期格式打印

使用strftime()函數將時間格式化爲想要的格式。它的原型如下:

size_t strftime(
   char *strDest,
   size_t maxsize,
   const char *format,
   const struct tm *timeptr 
);

例子:

strftime(str,100,"It is now %I %p",ptr);
printf(str);

其運行結果爲:
It is now 4PM
例子:

strftime( tmpbuf, 128, "Today is %A, day %d of %B in the year %Y.\n", newtime);
printf(tmpbuf);

運行結果:
Today is Saturday, day 30 of July in the year 2005.

分解時間轉化爲日曆時間

分解時間,在C/C++中指tm結構。我們可以使用mktime()函數將tm結構轉化爲日曆時間。其函數原型如下:

time_t mktime(struct tm * timeptr);

< sys/time.h >的計時函數

除了上述的標準C/C++用到的時間函數外,Linux系統也提供了一個函數,可以精確到微秒。

這就是gettimeofday函數,它獲得的時間精確到微秒(1e-6 s)量級。在一段代碼前後分別使用如下:

struct timeval tv_begin, tv_end;
gettimeofday(&tv_begin, NULL);
foo();
gettimeofday(&tv_end, NULL);

結構體timeval的定義爲:

struct timeval{
long int tv_sec; // 秒數
long int tv_usec; // 微秒數
}

time只能返回秒級的返回值,而該結構體能精確到微秒級。
該函數和time函數一樣都是按真實世界的時間來計算的。

總結

本文介紹了C/C++中的有關日期和時間的概念,並通過各種實例講述了這些函數和數據結構的使用方法。如果要測試優化的程序的運行效率,一般測量進程在cpu上使用的時間片之和,可以用clock函數,clock函數並不代表真實世界的時間。真實世界的時間則是time或者gettimeofday函數得到的,它們也可以用於日期的顯示。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章