c++ 时间类型详解(time_t和tm)
我們?cè)诰幊讨锌赡軙?huì)經(jīng)常用到時(shí)間,比如取得系統(tǒng)的時(shí)間(獲取系統(tǒng)的年、月、日、時(shí)、分、秒,星期等),或者是隔一段時(shí)間去做某事,那么我們就用到一些時(shí)間函數(shù)。
linux下存儲(chǔ)時(shí)間常見(jiàn)的有兩種存儲(chǔ)方式,一個(gè)是從1970年到現(xiàn)在經(jīng)過(guò)了多少秒,一個(gè)是用一個(gè)結(jié)構(gòu)來(lái)分別存儲(chǔ)年月日時(shí)分秒的。
time_t 這種類型就是用來(lái)存儲(chǔ)從1970年到現(xiàn)在經(jīng)過(guò)了多少秒,要想更精確一點(diǎn),可以用結(jié)構(gòu)struct timeval,它精確到微妙。
struct timeval {long tv_sec; /*秒*/long tv_usec; /*微秒*/ }; timeval {long tv_sec; /*秒*/long tv_usec; /*微秒*/ };而直接存儲(chǔ)年月日的是一個(gè)結(jié)構(gòu):
struct tm {int tm_sec; /*秒,正常范圍0-59, 但允許至61*/int tm_min; /*分鐘,0-59*/int tm_hour; /*小時(shí), 0-23*/int tm_mday; /*日,即一個(gè)月中的第幾天,1-31*/int tm_mon; /*月, 從一月算起,0-11*/ 1+p->tm_mon;int tm_year; /*年, 從1900至今已經(jīng)多少年*/ 1900+ p->tm_year;int tm_wday; /*星期,一周中的第幾天, 從星期日算起,0-6*/int tm_yday; /*從今年1月1日到目前的天數(shù),范圍0-365*/int tm_isdst; /*日光節(jié)約時(shí)間的旗標(biāo)*/ }; tm {int tm_sec; /*秒,正常范圍0-59, 但允許至61*/int tm_min; /*分鐘,0-59*/int tm_hour; /*小時(shí), 0-23*/int tm_mday; /*日,即一個(gè)月中的第幾天,1-31*/int tm_mon; /*月, 從一月算起,0-11*/ 1+p->tm_mon;int tm_year; /*年, 從1900至今已經(jīng)多少年*/ 1900+ p->tm_year;int tm_wday; /*星期,一周中的第幾天, 從星期日算起,0-6*/int tm_yday; /*從今年1月1日到目前的天數(shù),范圍0-365*/int tm_isdst; /*日光節(jié)約時(shí)間的旗標(biāo)*/ };需要特別注意的是,年份是從1900年起至今多少年,而不是直接存儲(chǔ)如2011年,月份從0開(kāi)始的,0表示一月,星期也是從0開(kāi)始的, 0表示星期日,1表示星期一。
下面介紹一下我們常用的時(shí)間函數(shù):
#include <time.h> char *asctime(const struct tm* timeptr); <time.h> char *asctime(const struct tm* timeptr);將結(jié)構(gòu)中的信息轉(zhuǎn)換為真實(shí)世界的時(shí)間,以字符串的形式顯示
char *ctime(const time_t *timep); *ctime(const time_t *timep);將timep轉(zhuǎn)換為真是世界的時(shí)間,以字符串顯示,它和asctime不同就在于傳入的參數(shù)形式不一樣
double difftime(time_t time1, time_t time2); difftime(time_t time1, time_t time2);返回兩個(gè)時(shí)間相差的秒數(shù)
int gettimeofday(struct timeval *tv, struct timezone *tz); gettimeofday(struct timeval *tv, struct timezone *tz);返回當(dāng)前距離1970年的秒數(shù)和微妙數(shù),后面的tz是時(shí)區(qū),一般不用
struct tm* gmtime(const time_t *timep); tm* gmtime(const time_t *timep);將time_t表示的時(shí)間轉(zhuǎn)換為沒(méi)有經(jīng)過(guò)時(shí)區(qū)轉(zhuǎn)換的UTC時(shí)間,是一個(gè)struct tm結(jié)構(gòu)指針
stuct tm* localtime(const time_t *timep);* localtime(const time_t *timep);和gmtime類似,但是它是經(jīng)過(guò)時(shí)區(qū)轉(zhuǎn)換的時(shí)間。
time_t mktime(struct tm* timeptr); mktime(struct tm* timeptr);將struct tm 結(jié)構(gòu)的時(shí)間轉(zhuǎn)換為從1970年至今的秒數(shù)
time_t time(time_t *t); time(time_t *t);取得從1970年1月1日至今的秒數(shù)。
上面是簡(jiǎn)單的介紹,下面通過(guò)實(shí)戰(zhàn)來(lái)看看這些函數(shù)的用法:
/*gettime1.c*/ #include <time.h>int main() {time_t timep;time(&timep); /*獲取time_t類型的當(dāng)前時(shí)間*//*用gmtime將time_t類型的時(shí)間轉(zhuǎn)換為struct tm類型的時(shí)間按,//沒(méi)有經(jīng)過(guò)時(shí)區(qū)轉(zhuǎn)換的UTC時(shí)間然后再用asctime轉(zhuǎn)換為我們常見(jiàn)的格式 Fri Jan 11 17:25:24 2008*/printf("%s", asctime(gmtime(&timep)));return 0; } #include <time.h>int main() {time_t timep;time(&timep); /*獲取time_t類型的當(dāng)前時(shí)間*//*用gmtime將time_t類型的時(shí)間轉(zhuǎn)換為struct tm類型的時(shí)間按,//沒(méi)有經(jīng)過(guò)時(shí)區(qū)轉(zhuǎn)換的UTC時(shí)間然后再用asctime轉(zhuǎn)換為我們常見(jiàn)的格式 Fri Jan 11 17:25:24 2008*/printf("%s", asctime(gmtime(&timep)));return 0; }編譯并運(yùn)行:
$gcc -o gettime1 gettime1.c $./gettime1 Fri Jan 11 17:04:08 2008-o gettime1 gettime1.c $./gettime1 Fri Jan 11 17:04:08 2008下面是直接把time_t類型的轉(zhuǎn)換為我們常見(jiàn)的格式:
/* gettime2.c*/ #include <time.h>int main() {time_t timep;time(&timep); /*獲取time_t類型當(dāng)前時(shí)間*/ /*轉(zhuǎn)換為常見(jiàn)的字符串:Fri Jan 11 17:04:08 2008*/printf("%s", ctime(&timep));return 0; } #include <time.h>int main() {time_t timep;time(&timep); /*獲取time_t類型當(dāng)前時(shí)間*/ /*轉(zhuǎn)換為常見(jiàn)的字符串:Fri Jan 11 17:04:08 2008*/printf("%s", ctime(&timep));return 0; }編譯并運(yùn)行:
$gcc -o gettime2 gettime2.c $./gettime2 Sat Jan 12 01:25:29 2008-o gettime2 gettime2.c $./gettime2 Sat Jan 12 01:25:29 2008我看了一本書(shū)上面說(shuō)的這兩個(gè)例子如果先后執(zhí)行的話,兩個(gè)的結(jié)果除了秒上有差別之外(執(zhí)行程序需要時(shí)間),應(yīng)該是一樣的,可是我這里執(zhí)行卻發(fā)現(xiàn)差了很長(zhǎng)時(shí)間按,一個(gè)是周五,一個(gè)是周六,后來(lái)我用 date 命令執(zhí)行了一遍
$ date 六 1月 12 01:25:19 CST 2008六 1月 12 01:25:19 CST 2008我發(fā)現(xiàn)date和gettime2比較一致, 我估計(jì)可能gettime1并沒(méi)有經(jīng)過(guò)時(shí)區(qū)的轉(zhuǎn)換,它們是有差別的。
/*gettime3.c */ #include <time.h>int main() {char *wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};time_t timep;struct tm *p;time(&timep); /*獲得time_t結(jié)構(gòu)的時(shí)間,UTC時(shí)間*/p = gmtime(&timep); /*轉(zhuǎn)換為struct tm結(jié)構(gòu)的UTC時(shí)間*/printf("%d/%d/%d ", 1900 + p->tm_year, 1+ p->tm_mon, p->tm_mday);printf("%s %d:%d:%d\n", wday[p->tm_wday], p->tm_hour,p->tm_min, p->tm_sec);return 0; } #include <time.h>int main() {char *wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};time_t timep;struct tm *p;time(&timep); /*獲得time_t結(jié)構(gòu)的時(shí)間,UTC時(shí)間*/p = gmtime(&timep); /*轉(zhuǎn)換為struct tm結(jié)構(gòu)的UTC時(shí)間*/printf("%d/%d/%d ", 1900 + p->tm_year, 1+ p->tm_mon, p->tm_mday);printf("%s %d:%d:%d\n", wday[p->tm_wday], p->tm_hour,p->tm_min, p->tm_sec);return 0; }編譯并運(yùn)行:
$gcc -o gettime3 gettime3.c $./gettime3 2008/1/11 Fri 17:42:54-o gettime3 gettime3.c $./gettime3 2008/1/11 Fri 17:42:54從這個(gè)時(shí)間結(jié)果上來(lái)看,它和gettime1保持一致。
/*gettime4.c*/ #include <time.h>int main() {char *wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};time_t timep;struct tm *p;time(&timep); /*獲得time_t結(jié)構(gòu)的時(shí)間,UTC時(shí)間*/p = localtime(&timep); /*轉(zhuǎn)換為struct tm結(jié)構(gòu)的當(dāng)?shù)貢r(shí)間*/printf("%d/%d/%d ", 1900 + p->tm_year, 1+ p->tm_mon, p->tm_mday);printf("%s %d:%d:%d\n", wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);return 0; } #include <time.h>int main() {char *wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};time_t timep;struct tm *p;time(&timep); /*獲得time_t結(jié)構(gòu)的時(shí)間,UTC時(shí)間*/p = localtime(&timep); /*轉(zhuǎn)換為struct tm結(jié)構(gòu)的當(dāng)?shù)貢r(shí)間*/printf("%d/%d/%d ", 1900 + p->tm_year, 1+ p->tm_mon, p->tm_mday);printf("%s %d:%d:%d\n", wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);return 0; }編譯并運(yùn)行:
$gcc -o gettime4 gettime4.c $./gettime4 2008/1/12 Sat 1:49:29-o gettime4 gettime4.c $./gettime4 2008/1/12 Sat 1:49:29從上面的結(jié)果我們可以這樣說(shuō):
time, gmtime, asctime 所表示的時(shí)間都是UTC時(shí)間,只是數(shù)據(jù)類型不一樣,
而localtime, ctime 所表示的時(shí)間都是經(jīng)過(guò)時(shí)區(qū)轉(zhuǎn)換后的時(shí)間,它和你用系統(tǒng)命令date所表示的CST時(shí)間應(yīng)該保持一致。
/*gettime5.c*/ #include <time.h>int main() {time_t timep;struct tm *p;time(&timep); /*當(dāng)前time_t類型UTC時(shí)間*/printf("time():%d\n",timep);p = localtime(&timep); /*轉(zhuǎn)換為本地的tm結(jié)構(gòu)的時(shí)間按*/timep = mktime(p); /*重新轉(zhuǎn)換為time_t類型的UTC時(shí)間,這里有一個(gè)時(shí)區(qū)的轉(zhuǎn)換*/ //by lizp 錯(cuò)誤,沒(méi)有時(shí)區(qū)轉(zhuǎn)換, 將struct tm 結(jié)構(gòu)的時(shí)間轉(zhuǎn)換為從1970年至p的秒數(shù)printf("time()->localtime()->mktime(): %d\n", timep);return 0; } #include <time.h>int main() {time_t timep;struct tm *p;time(&timep); /*當(dāng)前time_t類型UTC時(shí)間*/printf("time():%d\n",timep);p = localtime(&timep); /*轉(zhuǎn)換為本地的tm結(jié)構(gòu)的時(shí)間按*/timep = mktime(p); /*重新轉(zhuǎn)換為time_t類型的UTC時(shí)間,這里有一個(gè)時(shí)區(qū)的轉(zhuǎn)換*/ //by lizp 錯(cuò)誤,沒(méi)有時(shí)區(qū)轉(zhuǎn)換, 將struct tm 結(jié)構(gòu)的時(shí)間轉(zhuǎn)換為從1970年至p的秒數(shù)printf("time()->localtime()->mktime(): %d\n", timep);return 0; }編譯并運(yùn)行:
$gcc -o gettime5 gettime5.c $./gettime5 time():1200074913 time()->localtime()->mktime(): 1200074913-o gettime5 gettime5.c $./gettime5 time():1200074913 time()->localtime()->mktime(): 1200074913這里面把UTC時(shí)間按轉(zhuǎn)換為本地時(shí)間,然后再把本地時(shí)間轉(zhuǎn)換為UTC時(shí)間,它們轉(zhuǎn)換的結(jié)果保持一致。
/*gettime6.c */ #include <time.h>int main() {time_t timep;struct tm *p;time(&timep); /*得到time_t類型的UTC時(shí)間*/printf("time():%d\n",timep);p = gmtime(&timep); /*得到tm結(jié)構(gòu)的UTC時(shí)間*/timep = mktime(p); /*轉(zhuǎn)換,這里會(huì)有時(shí)區(qū)的轉(zhuǎn)換*/ //by lizp 錯(cuò)誤,沒(méi)有時(shí)區(qū)轉(zhuǎn)換, 將struct tm 結(jié)構(gòu)的時(shí)間轉(zhuǎn)換為從1970年至p的秒數(shù)printf("time()->gmtime()->mktime(): %d\n", timep);return 0; } #include <time.h>int main() {time_t timep;struct tm *p;time(&timep); /*得到time_t類型的UTC時(shí)間*/printf("time():%d\n",timep);p = gmtime(&timep); /*得到tm結(jié)構(gòu)的UTC時(shí)間*/timep = mktime(p); /*轉(zhuǎn)換,這里會(huì)有時(shí)區(qū)的轉(zhuǎn)換*/ //by lizp 錯(cuò)誤,沒(méi)有時(shí)區(qū)轉(zhuǎn)換, 將struct tm 結(jié)構(gòu)的時(shí)間轉(zhuǎn)換為從1970年至p的秒數(shù)printf("time()->gmtime()->mktime(): %d\n", timep);return 0; }編譯并運(yùn)行:
$gcc -o gettime6 gettime6.c $./gettime6 time():1200075192 time()->gmtime()->mktime(): 1200046392-o gettime6 gettime6.c $./gettime6 time():1200075192 time()->gmtime()->mktime(): 1200046392從這里面我們可以看出,轉(zhuǎn)換后時(shí)間不一致了,計(jì)算一下,整整差了8個(gè)小時(shí)( (1200075192-1200046392)/3600 = 8),說(shuō)明mktime會(huì)把本地時(shí)間轉(zhuǎn)換為UTC時(shí)間,這里面本來(lái)就是UTC時(shí)間,于是再弄個(gè)時(shí)區(qū)轉(zhuǎn)換,結(jié)果差了8個(gè)小時(shí),用的時(shí)候應(yīng)該注意。
strftime() 函數(shù)將時(shí)間格式化
我們可以使用strftime()函數(shù)將時(shí)間格式化為我們想要的格式。它的原型如下:
size_t strftime(char *strDest,size_t maxsize,const char *format,const struct tm *timeptr ); strftime(char *strDest,size_t maxsize,const char *format,const struct tm *timeptr );我們可以根據(jù)format指向字符串中格式命令把timeptr中保存的時(shí)間信息放在strDest指向的字符串中,最多向strDest中存放maxsize個(gè)字符。該函數(shù)返回向strDest指向的字符串中放置的字符數(shù)。
函數(shù)strftime()的操作有些類似于sprintf():識(shí)別以百分號(hào)(%)開(kāi)始的格式命令集合,格式化輸出結(jié)果放在一個(gè)字符串中。格式化命令說(shuō)明串 strDest中各種日期和時(shí)間信息的確切表示方法。格式串中的其他字符原樣放進(jìn)串中。格式命令列在下面,它們是區(qū)分大小寫(xiě)的。
%a 星期幾的簡(jiǎn)寫(xiě) %A 星期幾的全稱 %b 月分的簡(jiǎn)寫(xiě) %B 月份的全稱 %c 標(biāo)準(zhǔn)的日期的時(shí)間串 %C 年份的后兩位數(shù)字 %d 十進(jìn)制表示的每月的第幾天 %D 月/天/年 %e 在兩字符域中,十進(jìn)制表示的每月的第幾天 %F 年-月-日 %g 年份的后兩位數(shù)字,使用基于周的年 %G 年分,使用基于周的年 %h 簡(jiǎn)寫(xiě)的月份名 %H 24小時(shí)制的小時(shí) %I 12小時(shí)制的小時(shí) %j 十進(jìn)制表示的每年的第幾天 %m 十進(jìn)制表示的月份 %M 十時(shí)制表示的分鐘數(shù) %n 新行符 %p 本地的AM或PM的等價(jià)顯示 %r 12小時(shí)的時(shí)間 %R 顯示小時(shí)和分鐘:hh:mm %S 十進(jìn)制的秒數(shù) %t 水平制表符 %T 顯示時(shí)分秒:hh:mm:ss %u 每周的第幾天,星期一為第一天 (值從0到6,星期一為0) %U 第年的第幾周,把星期日做為第一天(值從0到53) %V 每年的第幾周,使用基于周的年 %w 十進(jìn)制表示的星期幾(值從0到6,星期天為0) %W 每年的第幾周,把星期一做為第一天(值從0到53) %x 標(biāo)準(zhǔn)的日期串 %X 標(biāo)準(zhǔn)的時(shí)間串 %y 不帶世紀(jì)的十進(jìn)制年份(值從0到99) %Y 帶世紀(jì)部分的十制年份 %z,%Z 時(shí)區(qū)名稱,如果不能得到時(shí)區(qū)名稱則返回空字符。 %% 百分號(hào)a 星期幾的簡(jiǎn)寫(xiě) %A 星期幾的全稱 %b 月分的簡(jiǎn)寫(xiě) %B 月份的全稱 %c 標(biāo)準(zhǔn)的日期的時(shí)間串 %C 年份的后兩位數(shù)字 %d 十進(jìn)制表示的每月的第幾天 %D 月/天/年 %e 在兩字符域中,十進(jìn)制表示的每月的第幾天 %F 年-月-日 %g 年份的后兩位數(shù)字,使用基于周的年 %G 年分,使用基于周的年 %h 簡(jiǎn)寫(xiě)的月份名 %H 24小時(shí)制的小時(shí) %I 12小時(shí)制的小時(shí) %j 十進(jìn)制表示的每年的第幾天 %m 十進(jìn)制表示的月份 %M 十時(shí)制表示的分鐘數(shù) %n 新行符 %p 本地的AM或PM的等價(jià)顯示 %r 12小時(shí)的時(shí)間 %R 顯示小時(shí)和分鐘:hh:mm %S 十進(jìn)制的秒數(shù) %t 水平制表符 %T 顯示時(shí)分秒:hh:mm:ss %u 每周的第幾天,星期一為第一天 (值從0到6,星期一為0) %U 第年的第幾周,把星期日做為第一天(值從0到53) %V 每年的第幾周,使用基于周的年 %w 十進(jìn)制表示的星期幾(值從0到6,星期天為0) %W 每年的第幾周,把星期一做為第一天(值從0到53) %x 標(biāo)準(zhǔn)的日期串 %X 標(biāo)準(zhǔn)的時(shí)間串 %y 不帶世紀(jì)的十進(jìn)制年份(值從0到99) %Y 帶世紀(jì)部分的十制年份 %z,%Z 時(shí)區(qū)名稱,如果不能得到時(shí)區(qū)名稱則返回空字符。 %% 百分號(hào)如果想顯示現(xiàn)在是幾點(diǎn)了,并以12小時(shí)制顯示,就象下面這段程序:
#include "time.h" #include "stdio.h" int main(void) {struct tm *ptr;time_t lt;char str[80];lt=time(NULL);ptr=localtime(<);strftime(str,100,"It is now %I %p",ptr);printf(str);return 0; } "time.h" #include "stdio.h" int main(void) {struct tm *ptr;time_t lt;char str[80];lt=time(NULL);ptr=localtime(<);strftime(str,100,"It is now %I %p",ptr);printf(str);return 0; }其運(yùn)行結(jié)果為:
It is now 4PM is now 4PM而下面的程序則顯示當(dāng)前的完整日期:
#include<stdio.h> #include<string.h> #include<time.h> int main( void ) {struct tm *newtime;char tmpbuf[128];time_t lt1;time( <1 );newtime=localtime(<1);strftime( tmpbuf, 128, "Today is %A, day %d of %B in the year %Y.\n", newtime);printf(tmpbuf);return 0; }<stdio.h> #include<string.h> #include<time.h> int main( void ) {struct tm *newtime;char tmpbuf[128];time_t lt1;time( <1 );newtime=localtime(<1);strftime( tmpbuf, 128, "Today is %A, day %d of %B in the year %Y.\n", newtime);printf(tmpbuf);return 0; }總結(jié)
以上是生活随笔為你收集整理的c++ 时间类型详解(time_t和tm)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 构建安全可靠的微服务 | Nacos 在
- 下一篇: C++小游戏 双人贪吃蛇