c/c++ 提供了優秀的 時間時間 函數,初學時感受幾乎沒有地方須要用到時間,隨着學習的深刻就會發現time.h 在不少方面給咱們提供了便利。例如程序運行的時間測試,日曆的編寫等等....html

下面來認識一下time.hc++

time.h是C標準函數庫中獲取時間與日期、對時間與日期數據操做及格式化的頭文件。web

 

表示時間的三種數據類型

  • 日 歷時間(calendar time),是從一個標準時間點(epoch)到如今的時間通過的秒數,不包括插入閏秒對時間的調整。開始計時的標準時間點,各類編譯器通常使用1970 年1月1日0時0秒。日曆時間用數據類型time_t表示。time_t類型實際上通常是32位或64位整數類型。
  • 時鐘滴答數(clock tick),從進程啓動開始計時,所以這是相對時間。每秒鐘包含CLOCKS_PER_SEC(time.h中定義的常量,通常爲1000)個時鐘滴答。時鐘滴答數用數據類型clock_t表示。clock_t類型通常是32位整數類型。
  • 分解時間(broken-down time),用結構數據類型tm表示,tm包含下列結構成員:
Member Description
int tm_hour hour (0 – 23)
int tm_isdst 夏令時 enabled (> 0), disabled (= 0), or unknown (< 0)
int tm_mday day of the month (1 – 31)
int tm_min minutes (0 – 59)
int tm_mon month (0 – 11, 0 = January)
int tm_sec seconds (0 – 60, 60 = Leap second)
int tm_wday day of the week (0 – 6, 0 = Sunday)
int tm_yday day of the year (0 – 365)
int tm_year year since 1900
 
 
 

從計算機系統時鐘得到時間的方法安全

  • time_t time(time_t* timer)

             獲得從標準計時點(通常是1970年1月1日午夜)到當前時間的秒數。數據結構

  • clock_t clock(void)

            獲得從進程啓動到這次函數調用的累計的時鐘滴答數。函數

三種時間日期數據類型的轉換函數oop

  • struct tm* gmtime(const time_t* timer)

              從日曆時間time_t到分解時間tm的轉換。函數返回的是一個靜態分配的tm結構存儲空間,該存儲空間被gmtime, localtime與ctime函數所共用. 這些函數的每一次調用會覆蓋這塊tm結構存儲空間的內容。post

  • struct tm* gmtime_r(const time_t* timer, struct tm* result)

             該函數是gmtime函數的線程安全版本.學習

  • struct tm* localtime(const time_t* timer)

              從日曆時間time_t到分解時間tm的轉換,即結果數據已經調整到本地時區與夏令時。測試

  • time_t mktime(struct tm* ptm)

             從分解時間tm到日曆時間time_t的轉換。

  • time_t timegm(struct tm* brokentime)

             從分解時間tm(被視做UTC時間,不考慮本地時區設置)到日曆時間time_t的轉換。該函數較少被使用。

時間日期數據的格式化函數

  • char *asctime(const struct tm* tmptr)

             把分解時間tm輸出到字符串,結果的格式爲"Www Mmm dd hh:mm:ss yyyy",即「周幾 月份數 日數 小時數:分鐘數:秒鐘數 年份數」。函數返回的字符串爲靜態分配,長度不大於26,與ctime函數共用。函數的每次調用將覆蓋該字符串內容。

  • char* ctime(const time_t* timer)

            把日曆時間time_t timer輸出到字符串,輸出格式與asctime函數同樣.

  • size_t strftime(char* s, size_t n, const char* format, const struct tm* tptr)

            把分解時間tm轉換爲自定義格式的字符串,相似於常見的字符串格式輸出函數sprintf。

  • char * strptime(const char* buf, const char* format, struct tm* tptr)

            strftime的逆操做,把字符串按照自定義的格式轉換爲分解時間tm。

對時間數據的操做

  • double difftime(time_t timer2, time_t timer1)

             比較兩個日曆時間之差。

源代碼示例

打印當前時間到標準輸出流:

1 # include <stdio.h>
2 # include <time.h>
3 int main(void)
4 {
5 time_t  timer = time(NULL);
6 printf("ctime is %s\n", ctime(&timer));
7 return 0;
8 }
 

time函數介紹

一、函數名稱: localtime

函數原型: struct tm *localtime(const time_t *timer)

函數功能: 返回一個以tm結構表達的機器時間信息

函數返回: 以tm結構表達的時間,結構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;

};

參數說明: timer-使用time()函數得到的機器時間

二、函數名稱: asctime

函數原型: char* asctime(struct tm * ptr)

函數功能: 獲得機器時間(日期時間轉換爲ASCII碼)

函數返回: 返回的時間字符串格式爲:星期,月,日,小時:分:秒,年

參數說明: 結構指針ptr應經過函數localtime()和gmtime()獲得

三、函數名稱: ctime

函數原型: char *ctime(long time)

函數功能: 獲得日曆時間

函數返回: 返回字符串格式:星期,月,日,小時:分:秒,年

參數說明: time-該參數應由函數time得到

四、函數名稱: difftime

函數原型: double difftime(time_t time2, time_t time1)

函數功能: 獲得兩次機器時間差,單位爲秒

函數返回: 時間差,單位爲秒

參數說明: time1-機器時間一,time2-機器時間二.該參數應使用time函數得到

五、函數名稱: gmtime

函數原型: struct tm *gmtime(time_t *time)

函數功能: 獲得以結構tm表示的時間信息

函數返回: 以結構tm表示的時間信息指針

參數說明: time-用函數time()獲得的時間信息

六、函數名稱: time

函數原型: time_t time(time_t *timer)

函數功能: 獲得機器的日曆時間或者設置日曆時間

函數返回: 機器日曆時間

參數說明: timer=NULL時獲得機器日曆時間,timer=時間數值時,用於設置日曆時間,time_t是一個long類型

七、函數名稱: tzset

函數原型: void tzset(void)

函數功能: UNIX兼容函數,用於獲得時區,在DOS環境下無用途

函數返回:

參數說明:

 
 

time.h能幹什麼?

1.概念
Coordinated Universal Time(UTC):協調世界時,又稱爲世界標準時間,也就是你們所熟知的格林威治標準時間(Greenwich Mean Time,GMT)。好比,中國內地的時間與UTC的時差爲+8,也就是UTC+8。美國是UTC-5。

Calendar Time:日曆時間,是用「從一個標準時間點到此時的時間通過的秒數」來表示的時間。這個標準時間點對不一樣的編譯器來講會有所不一樣,但對一個編譯系統來 說,這個標準時間點是不變的,該編譯系統中的時間對應的日曆時間都經過該標準時間點來衡量,因此能夠說日曆時間是「相對時間」,可是不管你在哪個時區, 在同一時刻對同一個標準時間點來講,日曆時間都是同樣的。

epoch:時間點。時間點在標準C/C++中是一個整數,它用此時的時間和標準時間點相差的秒數(即日曆時間)來表示。

clock tick:時鐘計時單元(而不把它叫作時鐘滴答次數),一個時鐘計時單元的時間長短是由CPU控制的。一個clock tick不是CPU的一個時鐘週期,而是C/C++的一個基本計時單位。

咱們可使用ANSI標準庫中的time.h頭文件。這個頭文件中定義的時間和日期所使用的方法,不管是在結構定義,仍是命名,都具備明顯的C語言風格。下面,我將說明在C/C++中怎樣使用日期的時間功能。

2. 計時

C/C++中的計時函數是clock(),而與其相關的數據類型是clock_t。在MSDN中,查得對clock函數定義以下:

1 clock_t clock( void );

這個函數返回從「開啓這個程序進程」到「程序中調用clock()函數」時之間的CPU時鐘計時單元(clock tick)數,在MSDN中稱之爲掛鐘時間(wal-clock)。其中clock_t是用來保存時間的數據類型,在time.h文件中,咱們能夠找到對 它的定義:

1 #ifndef _CLOCK_T_DEFINED
2  typedef long clock_t;
3  #define _CLOCK_T_DEFINED
4  #endif

很明顯,clock_t是一個長整形數。在time.h文件中,還定義了一個常量CLOCKS_PER_SEC,它用來表示一秒鐘會有多少個時鐘計時單元,其定義以下:

1 #define CLOCKS_PER_SEC ((clock_t)1000)

能夠看到每過千分之一秒(1毫秒),調用clock()函數返回的值就加1。下面舉個例子,你可使用公式clock()/CLOCKS_PER_SEC來計算一個進程自身的運行時間:

1 void elapsed_time()
2  {
3  printf("Elapsed time:%u secs./n",clock()/CLOCKS_PER_SEC);
4  }

固然,你也能夠用clock函數來計算你的機器運行一個循環或者處理其它事件到底花了多少時間:

1 #include 「stdio.h」
2  #include 「stdlib.h」
3  #include 「time.h」
4  
5 int main( void )
6  {
7  long i = 10000000L;
8  clock_t start, finish;
9  double duration;
10  /* 測量一個事件持續的時間*/
11  printf( "Time to do %ld empty loops is ", i );
12  start = clock();
13  while( i-- ) ;
14  finish = clock();
15  duration = (double)(finish - start) / CLOCKS_PER_SEC;
16  printf( "%f seconds/n", duration );
17  system("pause");
18  }

在筆者的機器上,運行結果以下:

Time to do 10000000 empty loops is 0.03000 seconds

上面咱們看到時鐘計時單元的長度爲1毫秒,那麼計時的精度也爲1毫秒,那麼咱們可不能夠經過改變CLOCKS_PER_SEC的定義,經過把它定義的大一些,從而使計時精度更高呢?經過嘗試,你會發現這樣是不行的。在標準C/C++中,最小的計時單位是一毫秒。

3.與日期和時間相關的數據結構

在標準C/C++中,咱們可經過tm結構來得到日期和時間,tm結構在time.h中的定義以下:

#ifndef _TM_DEFINED
struct tm {
int tm_sec; /* 秒 – 取值區間爲[0,59] */
int tm_min; /* 分 - 取值區間爲[0,59] */
int tm_hour; /* 時 - 取值區間爲[0,23] */
int tm_mday; /* 一個月中的日期 - 取值區間爲[1,31] */
int tm_mon; /* 月份(從一月開始,0表明一月) - 取值區間爲[0,11] */
int tm_year; /* 年份,其值等於實際年份減去1900 */
int tm_wday; /* 星期 – 取值區間爲[0,6],其中0表明星期天,1表明星期一,以此類推 */
int tm_yday; /* 從每一年的1月1日開始的天數 – 取值區間爲[0,365],其中0表明1月1日,1表明1月2日,以此類推 */
int tm_isdst; /* 夏令時標識符,實行夏令時的時候,tm_isdst爲正。不實行夏令時的進候,tm_isdst爲0;不瞭解狀況時,tm_isdst()爲負。*/
};

1 #define _TM_DEFINED
2 #endif

ANSI C標準稱使用tm結構的這種時間表示爲分解時間(broken-down time)。

而日曆時間(Calendar Time)是經過time_t數據類型來表示的,用time_t表示的時間(日曆時間)是從一個時間點(例如:1970年1月1日0時0分0秒)到此時的秒數。在time.h中,咱們也能夠看到time_t是一個長整型數:

1 #ifndef _TIME_T_DEFINED
2  typedef long time_t; /* 時間值 */
3  #define _TIME_T_DEFINED /* 避免重複定義 time_t */
4  #endif

你們可能會產生疑問:既然time_t其實是長整型,到將來的某一天,從一個時間點(通常是1970年1月1日0時0分0秒)到那時的秒數(即日 歷時間)超出了長整形所能表示的數的範圍怎麼辦?對time_t數據類型的值來講,它所表示的時間不能晚於2038年1月18日19時14分07秒。爲了 可以表示更久遠的時間,一些編譯器廠商引入了64位甚至更長的整形數來保存日曆時間。好比微軟在Visual C++中採用了__time64_t數據類型來保存日曆時間,並經過_time64()函數來得到日曆時間(而不是經過使用32位字的time()函 數),這樣就能夠經過該數據類型保存3001年1月1日0時0分0秒(不包括該時間點)以前的時間。

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

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

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

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

經過查閱MSDN,咱們能夠知道Microsoft C/C++ 7.0中時間點的值(time_t對象的值)是從1899年12月31日0時0分0秒到該時間點所通過的秒數,而其它各類版本的Microsoft C/C++和全部不一樣版本的Visual C++都是計算的從1970年1月1日0時0分0秒到該時間點所通過的秒數。

4.與日期和時間相關的函數及應用
在本節,我將向你們展現怎樣利用time.h中聲明的函數對時間進行操做。這些操做包括取當前時間、計算時間間隔、以不一樣的形式顯示時間等內容。

4.1 得到日曆時間

咱們能夠經過time()函數來得到日曆時間(Calendar Time),其原型爲:

1 time_t time(time_t * timer);

若是你已經聲明瞭參數timer,你能夠從參數timer返回如今的日曆時間,同時也能夠經過返回值返回如今的日曆時間,即從一個時間點(例 如:1970年1月1日0時0分0秒)到如今此時的秒數。若是參數爲空(NUL),函數將只經過返回值返回如今的日曆時間,好比下面這個例子用來顯示當前 的日曆時間:

1 #include "time.h"
2  #include "stdio.h"
3  int main(void)
4  {
5  struct tm *ptr;
6  time_t lt;
7  lt =time(NUL);
8  printf("The Calendar Time now is %d/n",lt);
9  return 0;
10  }

 

運行的結果與當時的時間有關,我當時運行的結果是:

The Calendar Time now is 1122707619

其中1122707619就是我運行程序時的日曆時間。即從1970年1月1日0時0分0秒到此時的秒數。

4.2 得到日期和時間

這裏說的日期和時間就是咱們平時所說的年、月、日、時、分、秒等信息。從第2節咱們已經知道這些信息都保存在一個名爲tm的結構體中,那麼如何將一個日曆時間保存爲一個tm結構的對象呢?

其中可使用的函數是gmtime()和localtime(),這兩個函數的原型爲:

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

 

其中gmtime()函數是將日曆時間轉化爲世界標準時間(即格林尼治時間),並返回一個tm結構體來保存這個時間,而localtime()函數 是將日曆時間轉化爲本地時間。好比如今用gmtime()函數得到的世界標準時間是2005年7月30日7點18分20秒,那麼我用 localtime()函數在中國地區得到的本地時間會比世界標準時間晚8個小時,即2005年7月30日15點18分20秒。下面是個例子:

1 #include "time.h"
2  #include "stdio.h"
3  int main(void)
4  {
5  struct tm *local;
6  time_t t;
7  t=time(NUL);
8  local=localtime(&t);
9  printf("Local hour is: %d/n",local->tm_hour);
10  local=gmtime(&t);
11  printf("UTC hour is: %d/n",local->tm_hour);
12  return 0;
13  }

 

運行結果是:

Local hour is: 15
UTC hour is: 7

4.3 固定的時間格式

咱們能夠經過asctime()函數和ctime()函數將時間以固定的格式顯示出來,二者的返回值都是char*型的字符串。返回的時間格式爲:

星期幾 月份 日期 時:分:秒 年/n/0
例如:Wed Jan 02 02:03:55 1980/n/0

其中/n是一個換行符,/0是一個空字符,表示字符串結束。下面是兩個函數的原型:

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

 

其中asctime()函數是經過tm結構來生成具備固定格式的保存時間信息的字符串,而ctime()是經過日曆時間來生成時間字符串。這樣的 話,asctime()函數只是把tm結構對象中的各個域填到時間字符串的相應位置就好了,而ctime()函數須要先參照本地的時間設置,把日曆時間轉 化爲本地時間,而後再生成格式化後的字符串。在下面,若是t是一個非空的time_t變量的話,那麼:

1 printf(ctime(&t));

等價於:

1 struct tm *ptr;
2  ptr=localtime(&t);
3  printf(asctime(ptr));

那麼,下面這個程序的兩條printf語句輸出的結果就是不一樣的了(除非你將本地時區設爲世界標準時間所在的時區):

1 #include "time.h"
2  #include "stdio.h"
3  int main(void)
4  {
5  struct tm *ptr;
6  time_t lt;
7  lt =time(NUL);
8  ptr=gmtime(<);
9  printf(asctime(ptr));
10  printf(ctime(<));
11  return 0;
12  }

運行結果:

Sat Jul 30 08:43:03 2005
Sat Jul 30 16:43:03 2005

4.4 自定義時間格式

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

1 size_t strftime(
2  char *strDest,
3  size_t maxsize,
4  const char *format,
5  const struct tm *timeptr
6  );

咱們能夠根據format指向字符串中格式命令把timeptr中保存的時間信息放在strDest指向的字符串中,最多向strDest中存放maxsize個字符。該函數返回向strDest指向的字符串中放置的字符數。

函數strftime()的操做有些相似於sprintf():識別以百分號(%)開始的格式命令集合,格式化輸出結果放在一個字符串中。格式化命 令說明串strDest中各類日期和時間信息的確切表示方法。格式串中的其餘字符原樣放進串中。格式命令列在下面,它們是區分大小寫的。

%a 星期幾的簡寫
%A 星期幾的全稱
%b 月分的簡寫
%B 月份的全稱
%c 標準的日期的時間串
%C 年份的後兩位數字
%d 十進制表示的每個月的第幾天
%D 月/天/年
%e 在兩字符域中,十進制表示的每個月的第幾天
%F 年-月-日
%g 年份的後兩位數字,使用基於周的年
%G 年分,使用基於周的年
%h 簡寫的月份名
%H 24小時制的小時
%I 12小時制的小時
%j 十進制表示的每一年的第幾天
%m 十進制表示的月份
%M 十時製表示的分鐘數
%n 新行符
%p 本地的AM或PM的等價顯示
%r 12小時的時間
%R 顯示小時和分鐘:hh:mm
%S 十進制的秒數
%t 水平製表符
%T 顯示時分秒:hh:mm:ss
%u 每週的第幾天,星期一爲第一天 (值從0到6,星期一爲0)
%U 第年的第幾周,把星期日作爲第一天(值從0到53)
%V 每一年的第幾周,使用基於周的年
%w 十進制表示的星期幾(值從0到6,星期天爲0)
%W 每一年的第幾周,把星期一作爲第一天(值從0到53)
%x 標準的日期串
%X 標準的時間串
%y 不帶世紀的十進制年份(值從0到99)
%Y 帶世紀部分的十進制年份
%z,%Z 時區名稱,若是不能獲得時區名稱則返回空字符。
%% 百分號

若是想顯示如今是幾點了,並以12小時制顯示,就象下面這段程序:

1 #include 「time.h」
2  #include 「stdio.h」
3  int main(void)
4  {
5  struct tm *ptr;
6  time_t lt;
7  char str[80];
8  lt=time(NUL);
9  ptr=localtime(<);
10  strftime(str,100,"It is now %I %p",ptr);
11  printf(str);
12  return 0;
13  }

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

而下面的程序則顯示當前的完整日期:

1 #include <stdio.h>
2  #include <time.h>
3  
4 void main( void )
5  {
6  struct tm *newtime;
7  char tmpbuf[128];
8  time_t lt1;
9  time( <1 );
10  newtime=localtime(<1);
11  strftime( tmpbuf, 128, "Today is %A, day %d of %B in the year %Y./n", newtime);
12  printf(tmpbuf);
13  }

運行結果:

Today is Saturday, day 30 of July in the year 2005.

4.5 計算持續時間的長度

有時候在實際應用中要計算一個事件持續的時間長度,好比計算打字速度。在第1節計時部分中,我已經用clock函數舉了一個例子。Clock()函數能夠精確到毫秒級。同時,咱們也可使用difftime()函數,但它只能精確到秒。該函數的定義以下:

1 double difftime(time_t time1, time_t time0);

雖然該函數返回的以秒計算的時間間隔是double類型的,但這並不說明該時間具備同double同樣的精確度,這是由它的參數以爲的(time_t是以秒爲單位計算的)。好比下面一段程序: