時(shí)間和日期
由UNIX內(nèi)核提供的基本時(shí)間服務(wù)是計(jì)算自協(xié)調(diào)世界時(shí)(Coordinated Universal Time,UTC)公元1970年1月1日00:00:00這一特定 時(shí)間以來(lái)經(jīng)過的秒數(shù)逃沿。1.10節(jié)中曾提及這種秒數(shù)是以數(shù)據(jù)類型time_t表示 的烫幕,我們稱它們?yōu)槿諝v時(shí)間。日歷時(shí)間包括時(shí)間和日期澡腾。UNIX在這方 面與其他操作系統(tǒng)的區(qū)別是:(a)以協(xié)調(diào)統(tǒng)一時(shí)間而非本地時(shí)間計(jì) 時(shí);(b)可自動(dòng)進(jìn)行轉(zhuǎn)換沸伏,如變換到夏令時(shí);(c)將時(shí)間和日期作為 一個(gè)量值保存。
一般由函數(shù)int clock_gettime(clockid_t, struct timespec *)獲取特定時(shí)鐘的時(shí)間动分,常用如下4種時(shí)鐘:
CLOCK_REALTIME 統(tǒng)當(dāng)前時(shí)間毅糟,從1970年1.1日算起
CLOCK_MONOTONIC 系統(tǒng)的啟動(dòng)時(shí)間,不能被設(shè)置
CLOCK_PROCESS_CPUTIME_ID 本進(jìn)程運(yùn)行時(shí)間
CLOCK_THREAD_CPUTIME_ID 本線程運(yùn)行時(shí)間
struct tm *localtime(const time_t *clock); //線程不安全
struct tm* localtime_r( const time_t* timer, struct tm* result );//線程安全
size_t strftime (char* ptr, size_t maxsize, const char* format,const struct tm* timeptr );
time函數(shù)返回當(dāng)前時(shí)間和日期澜公。
#include <time.h>
time_t time(time_t *calptr);
返回值:若成功姆另,返回時(shí)間值;若出錯(cuò),返回-1 時(shí)間值作為函數(shù)值返回坟乾。如果參數(shù)非空迹辐,則時(shí)間值也存放在由calptr
指向的單元內(nèi)。
POSXI.1的實(shí)時(shí)擴(kuò)展增加了對(duì)多個(gè)系統(tǒng)時(shí)鐘的支持甚侣。在Single UNIX
Specification V4中明吩,控制這些時(shí)鐘的接口從可選組被移至基本組。時(shí)鐘 通過clockid_t類型進(jìn)行標(biāo)識(shí)殷费。圖6-8給出了標(biāo)準(zhǔn)值印荔。
clock_gettime函數(shù)可用于獲取指定時(shí)鐘的時(shí)間低葫,返回的時(shí)間在4.2節(jié) 介紹的timespec結(jié)構(gòu)中,它把時(shí)間表示為秒和納秒仍律。
#include <sys/time.h>
int clock_gettime(clockid_t clock_id, struct timespec *tsp);
寫一段簡(jiǎn)單的代碼
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
int main() {
time_t time_unix = time(NULL);
printf("this code is intended for time\n");
printf("unix CST: %ld\n", time_unix);
/* test clock_gettime. */
struct timespec time_sys;
int ret = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &time_sys);
printf("tv_nsec: %ld ns, tv_sec: %ld s\n", time_sys.tv_nsec, time_sys.tv_sec);
return 0;
}
當(dāng)時(shí)鐘ID設(shè)置為CLOCK_REALTIME時(shí)嘿悬,clock_gettime函數(shù)提供了
與time函數(shù)類似的功能,不過在系統(tǒng)支持高精度時(shí)間值的情況下水泉, clock_gettime可能比time函數(shù)得到更高精度的時(shí)間值善涨。
#include <sys/time.h>
int clock_getres(clockid_t clock_id, struct timespec *tsp);
返回值:若成功,返回0;若出錯(cuò)茶行,返回-1 clock_getres函數(shù)把參數(shù)tsp指向的timespec結(jié)構(gòu)初始化為與clock_id參
數(shù)對(duì)應(yīng)的時(shí)鐘精度躯概。例如,如果精度為1毫秒畔师,則tv_sec字段就是0娶靡, tv_nsec字段就是1 000 000。
例如:
/*
* @Author: machineplay
* @Date: 2020-02-04 20:25:49
* @Description: only for fun
*/
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/utsname.h>
#include <time.h>
#include <sys/time.h>
#include <string.h>
/**
* main function.
* @param
* @return: 0
*/
int main(int argc, char *argv[]) {
/* test time. */
time_t now_time = time(NULL);
printf("time_t :%ld\n", now_time);
/* test sys_time. */
int ret = 0;
struct timespec time_sys;
clock_getres(CLOCK_PROCESS_CPUTIME_ID, &time_sys);
printf("process_time: %ld ns, %ld s\n", time_sys.tv_nsec, time_sys.tv_sec);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time_sys);
printf("process_time: %ld ns, %ld s\n", time_sys.tv_nsec, time_sys.tv_sec);
return 0;
}
精度為1000ns
要對(duì)特定的時(shí)鐘設(shè)置時(shí)間看锉,可以調(diào)用clock_settime函數(shù)姿锭。
要對(duì)特定的時(shí)鐘設(shè)置時(shí)間,可以調(diào)用clock_settime函數(shù)伯铣。
#include <sys/time.h>
int clock_settime(clockid_t clock_id, const struct timespec *tsp);
返回值:若成功呻此,返回0;若出錯(cuò),返回-1 我們需要適當(dāng)?shù)奶貦?quán)來(lái)更改時(shí)鐘值腔寡,但是有些時(shí)鐘是不能修改的焚鲜。
SUSv4指定gettimeofday函數(shù)現(xiàn)在已棄用。然而放前,一些程序仍然使用 這個(gè)函數(shù)忿磅,因?yàn)榕ctime函數(shù)相比,gettimeofday提供了更高的精度(可到 微秒級(jí))凭语。
#include <sys/time.h>
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
tzp的唯一合法值是NULL葱她,其他值將產(chǎn)生不確定的結(jié)果。某些平臺(tái)
支持用tzp說(shuō)明時(shí)區(qū)似扔,但這完全依實(shí)現(xiàn)而定吨些,Single UNIX Specification對(duì) 此并沒有定義。
gettimeofday函數(shù)以距特定時(shí)間(1970年1月1日00 : 00 : 00)的秒數(shù)的 方式將當(dāng)前時(shí)間存放在tp指向的timeval結(jié)構(gòu)中炒辉,而該結(jié)構(gòu)將當(dāng)前時(shí)間表 示為秒和微秒豪墅。
一旦取得這種從上述特定時(shí)間經(jīng)過的秒數(shù)的整型時(shí)間值后,通常要 調(diào)用函數(shù)將其轉(zhuǎn)換為分解的時(shí)間結(jié)構(gòu)辆脸,然后調(diào)用另一個(gè)函數(shù)生成人們可 讀的時(shí)間和日期但校。圖6-9說(shuō)明了各種時(shí)間函數(shù)之間的關(guān)系。(圖中以虛 線表示的3個(gè)函數(shù)localtime啡氢、mktime和strftime都受到環(huán)境變量TZ的影響状囱, 我們將在本節(jié)的最后部分對(duì)其進(jìn)行說(shuō)明。點(diǎn)劃線表示了如何從時(shí)間相關(guān) 的結(jié)構(gòu)獲得日歷時(shí)間倘是。)
個(gè)函數(shù)localtime和gmtime將日歷時(shí)間轉(zhuǎn)換成分解的時(shí)間亭枷,并將這 些存放在一個(gè)tm結(jié)構(gòu)中。
struct tm { /* a broken-down time */
int tm_sec; /* seconds after the minute: [0 -
60] */
int tm_min; /* minutes after the hour: [0 - 59]
*/
int tm_hour; /* hours after midnight: [0 - 23] */
int tm_mday; /* day of the month: [1 - 31] */
int tm_mon; /* months since January: [0 - 11]
*/
int tm_year; /* years since 1900 */
int tm_wday; /* days since Sunday: [0 - 6] */
int tm_yday; /* days since January 1: [0 - 365]
*/
int tm_isdst; /* daylight saving time flag: <0, 0,
>0 */ };
秒可以超過59的理由是可以表示潤(rùn)秒搀崭。注意叨粘,除了月日字段,其他 字段的值都以0開始瘤睹。如果夏令時(shí)生效升敲,則夏令時(shí)標(biāo)志值為正;如果為 非夏令時(shí)時(shí)間,則該標(biāo)志值為0;如果此信息不可用轰传,則其值為負(fù)驴党。
Single UNIX Specification的以前版本允許雙潤(rùn)秒,于是获茬, tm_sec值的有效范圍是0~61港庄。
UTC的正式定義不允許雙潤(rùn)秒,所以恕曲,現(xiàn)在tm_sec值的有效范圍定 義為0~60鹏氧。
#include <time.h>
struct tm *gmtime(const time_t *calptr); struct tm *localtime(const time_t *calptr);
兩個(gè)函數(shù)的返回值:指向分解的tm結(jié)構(gòu)的指針;若出錯(cuò),返回NULL localtime和gmtime之間的區(qū)別是:localtime將日歷時(shí)間轉(zhuǎn)換成本地時(shí)
間(考慮到本地時(shí)區(qū)和夏令時(shí)標(biāo)志)佩谣,而 gmtime 則將日歷時(shí)間轉(zhuǎn)換成 協(xié)調(diào)統(tǒng)一時(shí)間的年把还、月、日茸俭、時(shí)吊履、分、秒瓣履、周日分解結(jié)構(gòu)率翅。
函數(shù)mktime以本地時(shí)間的年、月袖迎、日等作為參數(shù)冕臭,將其變換成 time_t值。
#include <time.h>
time_t mktime(struct tm *tmptr);
返回值:若成功燕锥,返回日歷時(shí)間;若出錯(cuò)辜贵,返回-1
函數(shù)strftime是一個(gè)類似于printf的時(shí)間值函數(shù)。它非常復(fù)雜归形,可以
通過可用的多個(gè)參數(shù)來(lái)定制產(chǎn)生的字符串托慨。
#include <time.h>
size_t strftime(char *restrict buf, size_t maxsize,
const char *restrict format,
const struct tm *restrict tmptr);
size_t strftime_l(char *restrict buf, size_t maxsize,
const char *restrict format,
const struct tm *restrict tmptr, locale_t locale);
兩個(gè)函數(shù)的返回值:若有空間,返回存入數(shù)組的字符數(shù);否則暇榴,返回0
兩個(gè)較早的函數(shù)——asctime和ctime能用于產(chǎn)生一個(gè)26字節(jié)的可打 印的字符串厚棵,類似于date(1)命令默認(rèn)的輸出蕉世。然而,這些函數(shù)現(xiàn)在已 經(jīng)被標(biāo)記為棄用婆硬,因?yàn)樗鼈円资艿骄彌_區(qū)溢出問題的影響狠轻。
strftime_l允許調(diào)用者將區(qū)域指定為參數(shù),除此之外彬犯,strftime和 strftime_l函數(shù)是相同的向楼。strftime使用通過TZ環(huán)境變量指定的區(qū)域。
tmptr參數(shù)是要格式化的時(shí)間值谐区,由一個(gè)指向分解時(shí)間值tm結(jié)構(gòu)的 指針說(shuō)明湖蜕。格式化結(jié)果存放在一個(gè)長(zhǎng)度為maxsize個(gè)字符的buf數(shù)組中, 如果buf長(zhǎng)度足以存放格式化結(jié)果及一個(gè)null終止符宋列,則該函數(shù)返回在buf 中存放的字符數(shù)(不包括null終止符);否則該函數(shù)返回0昭抒。
format參數(shù)控制時(shí)間值的格式。如同printf函數(shù)一樣虚茶,轉(zhuǎn)換說(shuō)明的形 式是百分號(hào)之后跟一個(gè)特定字符戈鲁。format中的其他字符則按原樣輸出。 兩個(gè)連續(xù)的百分號(hào)在輸出中產(chǎn)生一個(gè)百分號(hào)嘹叫。與printf函數(shù)的不同之處 是婆殿,每個(gè)轉(zhuǎn)換說(shuō)明產(chǎn)生一個(gè)不同的定長(zhǎng)輸出字符串,在format字符串中沒有字段寬度修飾符罩扇。圖6-10中列出了37種ISO C規(guī)定的轉(zhuǎn)換說(shuō)明婆芦。
#include <iostream>
#include <time.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
int main() {
/* time of timeval. */
struct timeval now_time;
int ret = gettimeofday(&now_time, NULL);
printf("now_time since 1970: %d us, %ld s\n", now_time.tv_usec, now_time.tv_sec);
/* time of timespec. */
struct timespec time_spec;
/* struct of tm*/
struct tm detail_time;
struct tm *tm_ptr = &detail_time;
time_t tmp_time = time(NULL);
printf("time_t : %ld\n", tmp_time);
/* gmtime. */
tm_ptr = gmtime(&tmp_time);
/* show detail time. */
printf("year: %d\n, month: %d\n, day: %d\n, hour: %d\n, min: %d\n, second %d\n",
detail_time.tm_year,
detail_time.tm_mon,
detail_time.tm_mday,
detail_time.tm_hour,
detail_time.tm_min,
detail_time.tm_sec);
/* test mktime. */
tmp_time = mktime(tm_ptr);
printf("timt_t after mktime %ld\n", tmp_time);
/* change to localtime. */
tm_ptr = localtime(&tmp_time);
/* test strftime. */
char buf[255];
strftime(buf, sizeof(buf), "%c", tm_ptr);
printf("strftime time: %s\n", buf);
/* time */
memset(buf, 0, 255);
strftime(buf, sizeof(buf), "%Y%m%d,%H:%M:%S", tm_ptr);
printf("time: %s\n", buf);
return 0;
/* local time. */
}
strptime函數(shù)是strftime的反過來(lái)版本,把字符串時(shí)間轉(zhuǎn)換成分解
時(shí)間喂饥。
#include <time.h>
char *strptime(const char *restrict buf, const char
*restrict format,
struct tm *restrict tmptr);
所以記得strftime年月日時(shí)分秒
%Y-%m-%d %H:%M:%S