聲明:如果涉及侵權,請聯繫本人刪除侵權內容。
聲明:本文由本人以以往工作經驗爲依據,總結而得,如果錯誤,歡迎指正,便於後人參考,少走彎路。
Demo文件請移步github:Time Demo。
開發中經常會用到時間,針對不同應用,對時間的需求有所不同:
時間精度(計時等,秒級、毫秒級、微秒級、納秒級);
時間格式(RTC顯示等,年、月、日、時、分、秒的常用不同排列組合);
時間計時(週期報文的發送等);
時間點(鬧鐘等);
時間段(進程運行時間統計等);
目錄
1. 函數一覽表
函數 | 頭文件 | 解釋 |
---|---|---|
time() | <time.h> | 獲取秒數時間; 基於新紀元1970。 |
ftime() | <sys/timeb.h> | 獲取秒數和毫秒數; 基於新紀元1970; 有些標準已廢棄。 |
ctime()族 | <time.h> | 時間格式轉換; asctime(),ctime(),gmtime(),localtime(),mktime()...; 基於1900年; 不獲取時間。 |
gettimeofday()族 | <sys/time.h> | 操作秒和微妙; 基於新紀元1970。 |
clock_gettime()族 | <time.h> | 操作秒和納秒; 基於新紀元1970年; 多用於系統實時、相對、絕對等各類時間統計。 |
2. 結構體一覽表
結構體 | 頭文件 | 解釋 | 備註 |
---|---|---|---|
time_t | <time.h> | 長整型別名 | time()使用 |
timeb | <sys/timeb.h> | 包含毫秒的結構體 | ftime()使用 |
tm | <time.h> | 包含夏令時,一年中的哪天,星期幾,年,月,日,時,分,秒 | ctime族使用,包括asctime(),asctime_r(),gmtime(),gmtime_r(),localtime(),localtime_r(),mktime() |
timeval | <bits/time.h> | 秒和微妙 | gettimeofday()族使用 |
timezone | <sys/time.h> | 格林威治以西的時間(夏令時) | gettimeofday()族使用 |
clockid_t | <time.h> | 整型別名 | clock_gettime()族使用 |
timespec | <time.h> | 秒和納秒 | clock_gettime()族使用 |
3. 結構體介紹
3.1. time_t
//*** /usr/include/bits/types.h
#define __SLONGWORD_TYPE long int
//*** /usr/include/bits/typesizes.h
#define __TIME_T_TYPE __SLONGWORD_TYPE
//*** /usr/include/bits/types.h
__STD_TYPE __TIME_T_TYPE __time_t;/* Seconds since the Epoch. */
//*** /usr/include/time.h
typedef __time_t time_t;
- 開始計時時間:1970年1月1日0時0分0秒
- 要求該類型表達時間不晚於:2038年1月18日19時14分07秒
3.2. timeb
//*** /usr/include/sys/timeb.h
struct timeb {
time_t time;
unsigned short millitm;
short timezone;
short dstflag;
};
- time:存放秒級的值;
- millitm:存放一秒內的毫秒級的值;
- timezone:以格林威治以西的時間分鐘爲單位度量的本地時區(負值表示格林威治以東的時間分鐘)(UTC時間和本地時間的相差分鐘數);
- dstflag:如果非零,是夏令時時間;
- POSIX.1-2001表示:timezone和dstflag字段的內容是未指定的,避免依賴他們。
3.3. tm
//*** /usr/include/time.h
struct tm {
int tm_sec; /* Seconds (0-60) */
int tm_min; /* Minutes (0-59) */
int tm_hour; /* Hours (0-23) */
int tm_mday; /* Day of the month (1-31) */
int tm_mon; /* Month (0-11) */
int tm_year; /* Year - 1900 */
int tm_wday; /* Day of the week (0-6, Sunday = 0) */
int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */
int tm_isdst; /* Daylight saving time */
};
- tm_sec:0-60範圍內的真實秒值,60?;
- tm_min:0-59範圍內的真實分鐘值;
- tm_hour:0-23範圍內的真實小時值;
- tm_mday:1-31範圍內的真實日期日值;
- tm_mon:0-11範圍內的真實日期月值;
- tm_year:從1900年開始的年值是1900,不是1970;
- tm_wday:0-6範圍內的星期值,0代表週日;
- tm_yday:0-365範圍內的一年中的第幾天,0代表1月1日;
- tm_isdst:夏令時間
3.4. timeval
//*** /usr/include/bits/time.h
struct timeval
{
__time_t tv_sec;
__suseconds tv_usec;
};
- tv_sec:秒
- tv_usec:微秒
3.5. timezone
//*** /usr/include/sys/time.h
struct timezone
{
int tz_minuteswest;
int tz_dsttime;
};
- tz_minuteswest:以格林威治以西的時差,單位爲分鐘
- tz_dsttime:夏令時非零時有效
3.6. clockid_t
//*** /usr/include/bits/types.h
#define __S32_TYPE int
//*** /usr/include/bits/typesizes.h
#define __CLOCKID_T_TYPE __S32_TYPE
//*** /usr/include/bits/types.h
__STD_TYPE __CLOCK_T_TYPE __clock_t;
//*** /usr/include/time.h
typedef __clockid_t clockid_t;
3.7. timespec
//*** /usr/include/time.h
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
- tv_sec:秒;
- tv_nsec:納秒;
4. 函數介紹
4.1. time()
- MAN章節&頭文件&定義:
/* man 2 time */ #include <time.h> time_t time(time_t *tloc);
- 函數&參數&返回值描述:
- 函數描述:
返回從新紀元(1970-01-01 00:00:00 +0000 (UTC)開始的秒數。
- 參數描述:
如果tloc非NULL,則返回值也存儲在tloc指向的內存中。
- 返回值描述:
- 成功:返回從新紀元開始的秒數值;
- 失敗:返回-1,並設置errno;
- Demo&結果:
- Demo:
#include <stdio.h> #include <time.h> int main(void) { time_t m_tyTimeVal = 0; m_tyTimeVal = time(NULL); printf("%d\n",(int)m_tyTimeVal); return 0; }
- 結果:
/* 算算什麼時間... */ 1587039053
4.2. ftime()
-
MAN章節&頭文件&定義:
/* man 3 ftime */ #include <sys/timeb.h> int ftime(struct timeb *tp);
-
函數&參數&返回值描述:
- 函數描述:
以秒和毫秒的形式返回自新紀元(1970-01-01 00:00:00 +0000 (UTC))以來的當前時間。
- 參數描述:
傳出參數,存放獲取的時間值。
- 返回值描述:
- 總是返回0;
- POSIX.1-2001指定在某些系統文檔中錯誤返回-1。
-
Demo&結果:
- Demo:
/* gcc編譯需要struct timeb var格式定義. */ /* g++編譯可以timeb var格式直接定義. */ #include <stdio.h> #include <sys/timeb.h> int main(void) { int m_ulRet = 0; struct timeb m_stTimeVal; m_ulRet = ftime(&m_stTimeVal); printf(" ret : %d\n",m_ulRet); printf(" time : %d\n" " millitm : %d\n" "timezone : %d\n" " dstflag : %d\n", (int)m_stTimeVal.time, m_stTimeVal.millitm, m_stTimeVal.timezone, m_stTimeVal.dstflag); return 0; }
- 結果:
ret : 0 time : 1587031235 millitm : 84 timezone : 0 dstflag : 0
-
POSIX.1-2008刪除了ftime()的規範,廢棄不用了。
4.3. ctime()族
- MAN章節&頭文件&定義:
/* man 3 ctime/asctime/gmtime/localtime/mktime... */ #include <time.h> 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); 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); time_t mktime(struct tm *tm);
- 函數&參數&返回值描述:
- 函數描述:
- 這個族不會獲取時間,而是對已經獲取到的時間做格式轉換;
- localtime:將time_t類型的時間轉換爲tm類型本地時間;
- gmtime:將time_t類型的時間轉換爲tm類型的格林威治(GMT)時間,
- asctime:將tm類型時間轉換爲字符串型輸出;
- ctime:將time_t時間在內部轉換成tm時間,並轉成字符串輸出;
- mktime:將tm類型時間轉換成time_t類型;
- 在線程中應該使用對應函數的"_r"模式來處理,來避免線程安全問題;
- 參數描述:
- const tm*:傳入
- char *buf:傳出
- const time_t*傳入
- 返回值描述:
根據不同函數功能返回。
- Demo&結果:
- Demo:
#include <stdio.h> #include <time.h> #include <string.h> #include <stdlib.h> void printTm(const struct tm* tm) { printf("**%d-%d-%d:%d-%d-%d\n",tm->tm_year+1900,tm->tm_mon+1,\ tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec); printf("**week:%d\n",tm->tm_wday); printf("**yday:%d\n",tm->tm_yday); printf("**dst:%d\n",tm->tm_isdst); } int main(void) { time_t m_tyTimeVal = 0; time_t m_tyTimeTempVal = 0; struct tm* m_pstTmVal; char *m_pucTimeStr; m_pstTmVal = malloc(sizeof(struct tm)); m_pucTimeStr = malloc(200); printf("******************************** time() ***\n"); m_tyTimeTempVal = time(NULL); printf("**%d\n",(int)m_tyTimeTempVal); printf("****************************** gmtime() ***\n"); m_pstTmVal = gmtime(&m_tyTimeTempVal); printTm(m_pstTmVal); printf("*************************** localtime() ***\n"); m_pstTmVal = localtime(&m_tyTimeTempVal); printTm(m_pstTmVal); printf("***************************** asctime() ***\n"); m_pucTimeStr = asctime(m_pstTmVal); printf("**%s",m_pucTimeStr); printf("******************************* ctime() ***\n"); m_pucTimeStr = ctime(&m_tyTimeTempVal); printf("**%s",m_pucTimeStr); printf("****************************** mktime() ***\n"); m_tyTimeVal = mktime(m_pstTmVal); printf("**%d\n",(int)m_tyTimeVal); #if 0 if(m_pstTmVal) free(m_pstTmVal);//Bk?:這裏不能free,函數是怎麼返回結構體指針的? if(m_pucTimeStr) free(m_pucTimeStr); #endif return 0; }
- 結果:
# ./App ******************************** time() *** **206 ****************************** gmtime() *** **1970-1-1:0-3-26 **week:4 **yday:0 **dst:0 *************************** localtime() *** **1970-1-1:8-3-26 **week:4 **yday:0 **dst:0 ***************************** asctime() *** **Thu Jan 1 08:03:26 1970 ******************************* ctime() *** **Thu Jan 1 08:03:26 1970 ****************************** mktime() *** **206
4.4. gettimeofday()族
- MAN章節&頭文件&定義:
/* man 2 gettimeofday/settimeofday */ #include <sys/time.h> int gettimeofday(struct timeval *tv, struct timezone *tz); int settimeofday(const struct timeval *tv, const struct timezone *tz); // settimeofday(): _BSD_SOURCEs //Bk?:未確定用途
- 函數&參數&返回值描述:
- 函數描述:
- gettimeofday:獲取時間和時區信息;
- settimeofday:設置時間和時區;
- 參數描述:
- tv:包含秒和微秒信息,不使用時傳NULL,該變量爲NULL編譯時報警告;
- tz:包含時區和夏令時信息,該參數基本過時(有些系統獲取不到值),常傳NULL;
- 返回值描述:
- 0:成功;
- -1:失敗,並設置errno;
- Demo&結果:
- Demo:
#include <stdio.h> #include <sys/time.h> #include <time.h> #include <stdlib.h> int main(void) { struct timeval tv; system("date"); gettimeofday(&tv,NULL); printf("timeval:%ld.%ld\n\n",tv.tv_sec,tv.tv_usec); tv.tv_sec = 1587039053; tv.tv_usec = 0; printf("timeval:%ld.%ld\n\n",tv.tv_sec,tv.tv_usec); if(settimeofday(&tv,NULL) != 0) { perror("settimeofday"); } system("date"); gettimeofday(&tv,NULL); printf("timeval:%ld.%ld\n",tv.tv_sec,tv.tv_usec); return 0; }
- 結果:
# ./App Thu Jan 1 08:02:41 CST 1970 timeval:161.657774 timeval:1587039053.0 Thu Apr 16 20:10:53 CST 2020 timeval:1587039053.2744
- settimeofday在設置時間的時候,參數很容易出錯,導致設置失敗;
4.5. clock_gettime()族
- MAN章節&頭文件&定義:
/* man 3 clock_getres/clock_gettime/clock_settime */ #include <time.h> int clock_getres(clockid_t clk_id, struct timespec *res); int clock_gettime(clockid_t clk_id, struct timespec *tp); int clock_settime(clockid_t clk_id, const struct timespec *tp);
- 函數&參數&返回值描述:
- 函數描述:
- clock_getres:檢索指定clk_id類型的分辨率;
- clock_gettime:得到指定clk_id類型的時間;
- clock_settime:設置指定clk_id類型的時間;
- 參數描述:
- clk_id:某種時鐘類型
- CLOCK_REALTIME:系統實時時間,隨系統實時時間改變而改變;
- CLOCK_MONOTONIC:從系統啓動開始計時,不受系統時間被用戶改變的影響;
- CLOCK_PROCESS_CPUTIME_ID:本進程在系統CPU中運行的時間;
- CLOCK_THREAD_CPUTIME_ID:本進程在系統CPU中運行的時間。
- tp:時間值
- res:分辨率
- 返回值描述:
- 0:成功;
- -1:失敗,並設置errno。
- Demo&結果:
- Demo:
#include <stdio.h> #include <time.h> void printTm(const struct tm* tm) { printf("**%d-%d-%d:%d-%d-%d\n",tm->tm_year+1900,tm->tm_mon+1,\ tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec); printf("**week:%d\n",tm->tm_wday); printf("**yday:%d\n",tm->tm_yday); printf("**dst:%d\n",tm->tm_isdst); } int main(void) { struct timespec timeVal; clock_gettime(CLOCK_REALTIME,&timeVal); printf("time:%s\n",ctime(&timeVal.tv_sec)); printf("time: %ld.%ld\n",timeVal.tv_sec,timeVal.tv_nsec); return 0; }
- 結果:
# ./App time:Thu Jan 1 08:00:23 1970 time: 23.927505916
5. 其他時間函數
函數 | 解釋 |
---|---|
clock() | 返回程序使用的處理器時間的近似值 |
adjtime() | 調整系統時鐘 |
adjtimex() | 設置David L. Mills的時鐘調整算法的調整參數 |
clock_getcpuclockid() | TBD... |
pthread_getcpuclockid() | TBD... |
timeradd()族 | 操作timeval類型的兩個結構體變量; timeradd() timersub() timerclear() timerisset() timercmp() |
setitimer()族 | 爲進程提供三種間隔計時器,計時到達給進程發送信號; ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF |
timer_create()系列 | 創建一個間隔計時器 相關函數還有: timer_delete() timer_getoverrun() timer_settime timer_gettime |
timerfd_create()族 | 創建一個通過文件描述符傳遞計時器溢出通知的計時器 |
6. 疑問
- linuxOS能應用的最小時間精度,應用層可以保證的時間精度?
筆記:...
- 驗證:printf("%" PRId64"\n",m_tyTimeVal)?
筆記:...
- 格林威治&夏令時&時區?
筆記:...
- POSIX?
筆記:...
- 線程安全?
筆記:...
- 哪些結構體在將來某個時間點就不能使用了(time_t?)?
筆記:...
- ctime族多個函數返回結構體指針,返回的是那個區域(常量?堆區?棧?)?誰釋放?(突然感覺C語言不過關呀!)
筆記:...
- tm結構體tm_sec成員的值60什麼情況下應用?
筆記:...