C支持的平常時間格式或種類html
一、時間值 time_t安全
時間值是指從1970-01-01 00:00:00 +0000 (UTC) 這個時間點開始到當前時間的秒數。
在C語言中,用time_t
來表示一個秒數,查看頭文件能夠發現time_t
是對long
的一個重定義而已。
相關函數:time()
多線程
二、時間詳情 struct tmapp
有了具體的時間值time_t
,但存在着閱讀和理解不方便的問題,因此但願能夠把時間值轉化爲相應的年、月、日、時、分、秒等數據。
對應的結構體爲struct tm
。以下代碼:函數
1 struct tm { 2 int tm_sec; /* 秒,取值範圍(0~59),但當遇到閏秒時則會有60秒的取值。 */ 3 int tm_min; /* 分鐘數,取值範圍(0-59) */ 4 int tm_hour; /* 小時數,取值範圍(0-23) */ 5 int tm_mday; /* 當天在這個月中是第幾天,取值範圍(1-31) */ 6 int tm_mon; /* 當前月份是第幾個月,取值範圍(0-11) */ 7 int tm_year; /* 從1900年開始至今的年數,即(Year - 1900)的值 */ 8 int tm_wday; /* 當天在本週是第幾天,取值範圍(0-6, Sunday = 0) */ 9 int tm_yday; /* 當天在今年是第幾天,取值範圍(0-365, 1 Jan = 0) */ 10 int tm_isdst; /* 夏令時標記,值大於0表示夏令時生效;等於0表示夏令時失效;小於0表示數據不可用。 */ 11 char *tm_zone; /* 時區名稱,根據系統不一樣可能不被聲明或不一樣全名。 */ 12 };
相關函數:localtime()、gmtime()
this
三、時間字符串 char *spa
有了年、月、日等具體的數據,C也提供函數將數據轉爲轉爲可視的、有意義的字符串。
相關函數:線程
固定格式時間文本:ctime()、
asctime()
指針
自定義格式時間文本: strftime()
code
平常時間函數的調用關係
獲取當前時間值
time_t time(time_t *t);
time_t mktime(struct tm *tm);time()
能夠從當前系統中獲取時間值並返回,若是參數t
不爲NULL,則時間值一樣也會存儲中t
中。
若是函數執行異常,則返回-1,可經過errno
查詢出錯緣由。mktime()
則是將struct tm
逆解析爲time_t
的函數。
若是參數tm
是由用戶本身組裝的,則tm
中的tm_wday
和tm_yday
會在本函數執行後根據tm
中的tm_year``tm_mon
…等字段計算爲真實的值。
例子1:
1 #include <stdio.h> 2 #include <time.h> 3 4 int main () 5 { 6 time_t seconds; 7 8 seconds = time(NULL); 9 printf("自 1970-01-01 起的小時數 = %ld\n", seconds/3600); 10 11 return(0); 12 }
運行結果:
自 1970-01-01 起的小時數 = 420254
例子2:
1 #include <stdio.h> 2 #include <time.h> 3 4 int main () 5 { 6 int ret; 7 struct tm info; 8 char buffer[80]; 9 10 info.tm_year = 2001 - 1900; 11 info.tm_mon = 7 - 1; 12 info.tm_mday = 4; 13 info.tm_hour = 0; 14 info.tm_min = 0; 15 info.tm_sec = 1; 16 info.tm_isdst = -1; 17 18 ret = mktime(&info); 19 if( ret == -1 ) 20 { 21 printf("錯誤:不能使用 mktime 轉換時間。\n"); 22 } 23 else 24 { 25 strftime(buffer, sizeof(buffer), "%c", &info ); 26 print(buffer); 27 } 28 29 return(0); 30 }
運行結果:
Wed Jul 4 00:00:01 2001
獲取時間詳情
時間詳情也就是上文所說的struct tm
,manual中也把struct tm
稱爲broken-down time。相關函數:
struct tm *gmtime(const time_t *timep);
struct tm *gmtime_r(const time_t *timep, struct tm *result);struct tm *localtime(const time_t *timep);
struct tm *localtime_r(const time_t *timep, struct tm *result);
gmtime()
和localtime()
均可以把時間值轉換爲時間詳情,二者的區別在於gmtime()
所獲得的結果是世界標準時間Coordinated Universal Time (UTC)
;而localtime()
獲取的是本地時間。以北京時間爲例,gmtime()
獲得的結果比localtime()
要提早(早)8小時。
gmtime_r()
和localtime_r()
分別是gmtime()
及localtime()
的可重入實現版本。
爲何有了localtime()
還要有其餘兩個函數呢,由於localtime並非線程安全的,觀察localtime()
和localtime_r()
的調用發現,localtime在使用時,咱們只需定義一個指針,並不須要爲指針申請空間,而指針必需要指向內存空間纔可使用,其實申請空間的動做由函數本身完成,這樣在多線程的狀況下,若是有另外一個線程調用了這個函數,那麼指針指向的struct tm結構體的數據就會改變。在localtime_s()
與localtime_r()
調用時,定義的是struct tm的結構體,獲取到的時間已經保存在struct tm中,並不會受其餘線程的影響。
當函數執行錯誤時,則返回NULL,可經過errno
查詢出錯緣由。
例子1:
1 #include <stdio.h> 2 #include <time.h> 3 4 #define BST (+1) 5 #define CCT (+8) 6 7 int main () 8 { 9 10 time_t rawtime; 11 struct tm *info; 12 13 time(&rawtime); 14 /* 獲取 GMT 時間 */ 15 info = gmtime(&rawtime ); 16 17 printf("當前的世界時鐘:\n"); 18 printf("倫敦:%2d:%02d\n", (info->tm_hour+BST)%24, info->tm_min); 19 printf("中國:%2d:%02d\n", (info->tm_hour+CCT)%24, info->tm_min); 20 21 return(0); 22 }
運行結果:
當前的世界時鐘: 倫敦:15:58 中國:22:58
例子2:
1 #include <stdio.h> 2 #include <time.h> 3 4 int main () 5 { 6 time_t rawtime; 7 struct tm *info; 8 char buffer[80]; 9 10 time( &rawtime ); 11 12 info = localtime( &rawtime ); 13 printf("當前的本地時間和日期:%s", asctime(info)); 14 15 return(0); 16 }
運行結果:
當前的本地時間和日期:Sun Dec 10 22:57:38 2017
例子3:
1 #include <stdio.h> 2 #include <time.h> 3 4 int main() 5 { 6 time_t time_seconds = time(0); 7 struct tm now_time; 8 localtime_r(&time_seconds, &now_time); 9 10 printf("%d-%d-%d %d:%d:%d\n", now_time.tm_year + 1900, now_time.tm_mon + 1, 11 now_time.tm_mday, now_time.tm_hour, now_time.tm_min, now_time.tm_sec); 12 }
運行結果:
2017-12-11 14:28:11
格式化的時間字符串
char *asctime(const struct tm *tm);
char *asctime_r(const struct tm *tm, char *buf);char *ctime(const time_t *timep);
char *ctime_r(const time_t *timep, char *buf);
asctime()
能直接從時間詳情中計算出時間字符串,該字符串包含字符串終止符,計算出來的時間字符串格式是固定的,示例爲:Wed Jun 30 21:49:08 1993\n
。ctime()
則是asctime(localtime(time_t))
的封裝實現。
asctime_r()
和ctime_r()
分別是asctime()
及ctime()
的可重入實現版本。
注意:以上函數返回的字符串都會包含換行符\n
。
例子1:
1 #include <stdio.h> 2 #include <time.h> 3 4 int main () 5 { 6 time_t curtime; 7 8 time(&curtime); 9 10 printf("當前時間 = %s", ctime(&curtime)); 11 12 return(0); 13 }
運行結果:
當前時間 = Sun Dec 10 22:58:54 2017
例子2:
1 #include <stdio.h> 2 #include <string.h> 3 #include <time.h> 4 5 int main() 6 { 7 struct tm t; 8 9 t.tm_sec = 10; 10 t.tm_min = 10; 11 t.tm_hour = 6; 12 t.tm_mday = 25; 13 t.tm_mon = 2; 14 t.tm_year = 89; 15 t.tm_wday = 6; 16 17 puts(asctime(&t)); 18 19 return(0); 20 }
運行結果:
Sat Mar 25 06:10:10 1989
size_t strftime(char *s, size_t max, const char *format, const struct tm *tm);
C語言爲了格式化輸出時間信息又提供了強大的格式化函數strftime()
,支持按自定義的格式打印出完整可閱讀的時間信息,包括月份的全稱或簡稱,或只選擇某些關鍵時間值進行輸出。
參數s
指向格式化後的時間字符串。
參數max
表示時間字符串的最大字符數(含字符串終止符)。
參數format
表示時間字符串的格式化表達式。
參數tm
表示待格式化的時間詳情。
其中format
表達式支持格式化參數與字符混合使用,且所支持的格式化參數很是多,具體以下:
說明符 | 替換爲 | 實例 |
---|---|---|
%a | 縮寫的星期幾名稱 | Sun |
%A | 完整的星期幾名稱 | Sunday |
%b | 縮寫的月份名稱 | Mar |
%B | 完整的月份名稱 | March |
%c | 日期和時間表示法 | Sun Aug 19 02:56:02 2012 |
%d | 一月中的第幾天(01-31) | 19 |
%H | 24 小時格式的小時(00-23) | 14 |
%I | 12 小時格式的小時(01-12) | 05 |
%j | 一年中的第幾天(001-366) | 231 |
%m | 十進制數表示的月份(01-12) | 08 |
%M | 分(00-59) | 55 |
%p | AM 或 PM 名稱 | PM |
%S | 秒(00-61) | 02 |
%U | 一年中的第幾周,以第一個星期日做爲第一週的第一天(00-53) | 33 |
%w | 十進制數表示的星期幾,星期日表示爲 0(0-6) | 4 |
%W | 一年中的第幾周,以第一個星期一做爲第一週的第一天(00-53) | 34 |
%x | 日期表示法 | 08/19/12 |
%X | 時間表示法 | 02:50:06 |
%y | 年份,最後兩個數字(00-99) | 01 |
%Y | 年份 | 2012 |
%Z | 時區的名稱或縮寫 | CDT |
%% | 一個 % 符號 | % |
綜合例子:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 int main (int argc, char ** argv) { 5 time_t calendar_time = time(NULL); 6 printf("calendar_time :%ld \n", calendar_time); 7 8 char * calendar_str = ctime(&calendar_time); 9 printf("calendar_str :%s \n", calendar_str); 10 11 struct tm * tm_local = localtime(&calendar_time); 12 printf("localtime :year=%d mon=%d mday=%d hour=%d min=%d sec=%d wday=%d yday=%d isdst=%d \n", 13 tm_local->tm_year + 1900, tm_local->tm_mon + 1, tm_local->tm_mday, tm_local->tm_hour, tm_local->tm_min, tm_local->tm_sec, 14 tm_local->tm_wday, tm_local->tm_yday, tm_local->tm_isdst); 15 16 char * asc_time = asctime(tm_local); 17 printf("asc_time :%s", asc_time); 18 char * c_time = ctime(&calendar_time); 19 printf("c_time :%s", c_time); 20 21 time_t mk_time = mktime(tm_local); 22 printf("\nmk_time :%ld \n\n", mk_time); 23 24 25 char str_f_t [100]; 26 strftime(str_f_t, sizeof(str_f_t), "%G-%m-%d %H:%M:%S", tm_local); 27 printf("local :format=%s \n", str_f_t); 28 struct tm * gm_time = gmtime(&calendar_time); 29 strftime(str_f_t, sizeof(str_f_t), "%G-%m-%d %H:%M:%S", gm_time); 30 printf("gmtime :format=%s \n\n", str_f_t); 31 32 struct tm my_tm = {2,2,2,16,2,2015,0,0,0}; 33 time_t my_time_t = mktime(&my_tm); 34 printf("my yday:%d \n", my_tm.tm_yday); 35 36 return 0; 37 }
運行結果:
calendar_time :1512916710 calendar_str :Sun Dec 10 22:38:30 2017 localtime :year=2017 mon=12 mday=10 hour=22 min=38 sec=30 wday=0 yday=343 isdst=0 asc_time :Sun Dec 10 22:38:30 2017 c_time :Sun Dec 10 22:38:30 2017 mk_time :1512916710 local :format=2017-12-10 22:38:30 gmtime :format=2017-12-10 14:38:30 my yday:74
difftime
double difftime(time_t time1, time_t time2);
返回 time1 和 time2 之間相差的秒數 (time1 - time2)。這兩個時間是在日曆時間中指定的,表示了自紀元 Epoch(協調世界時 UTC:1970-01-01 00:00:00)起通過的時間。
1 #include <stdio.h> 2 #include <time.h> 3 #ifdef _WIN32 4 #include <Windows.h> 5 #else 6 #include <unistd.h> 7 #endif 8 9 int main () 10 { 11 time_t start_t, end_t; 12 double diff_t; 13 14 printf("程序啓動...\n"); 15 time(&start_t); 16 17 printf("休眠 5 秒...\n"); 18 sleep(5); 19 20 time(&end_t); 21 diff_t = difftime(end_t, start_t); 22 23 printf("執行時間 = %f\n", diff_t); 24 printf("程序退出...\n"); 25 26 return(0); 27 }
運行結果:
程序啓動... 休眠 5 秒... 執行時間 = 5.000000 程序退出...
clock
clock_t clock(void);
返回程序執行起(通常爲程序的開頭),處理器時鐘所使用的時間。爲了獲取 CPU 所使用的秒數,須要除以 CLOCKS_PER_SEC。在 32 位系統中,CLOCKS_PER_SEC 等於 1000000,該函數大約每 72 分鐘會返回相同的值。本方法有必定缺陷,在32bit機器上,運行時間較長達到(超過1小時),有可能出現計時錯誤。
clock()文檔說明以下:
Note that the time can wrap around. On a 32-bit system where CLOCKS_PER_SEC equals 1000000 this function will return the same value approximately every 72 minutes.
所以,當出現計時爲負數或者很小的數時,須要人爲憑經驗加上若干個72minutes……
因此這個函數仍是不要用了!
例子:
1 #include <time.h> 2 #include <stdio.h> 3 4 int main() 5 { 6 clock_t start_t, end_t; 7 double total_t; 8 int i; 9 10 start_t = clock(); 11 printf("程序啓動,start_t = %ld\n", start_t); 12 13 printf("開始一個大循環,start_t = %ld\n", start_t); 14 for(i=0; i< 10000000; i++) 15 { 16 } 17 end_t = clock(); 18 printf("大循環結束,end_t = %ld\n", end_t); 19 20 printf("CLOCKS_PER_SEC = %ld\n", CLOCKS_PER_SEC); 21 total_t = (double)(end_t - start_t) / CLOCKS_PER_SEC; 22 printf("CPU 佔用的總時間:%f\n", total_t ); 23 printf("程序退出...\n"); 24 25 return(0); 26 }
運行結果:
程序啓動,start_t = 549 開始一個大循環,start_t = 549 大循環結束,end_t = 25777 CLOCKS_PER_SEC = 1000000 CPU 佔用的總時間:0.025228 程序退出...
本文參考自:
http://sodino.com/2015/03/15/c-time/
http://www.runoob.com/cprogramming/c-standard-library-time-h.html