linux時間編程

1. time_t

time_t記錄自1970年1月1日凌晨以來的秒數,在Linux/Unix上定義爲long int類型,在32位系統上,time_t最多隻能記錄2,147,483,647秒,也就是說到了2038年將會產生溢出,但在64位系統上不會出現此問題。

time_t time(time_t *t);
例子如下:
  1. #include <stdio.h>  
  2. #include <time.h>  
  3.   
  4. int main(void)  
  5. {  
  6.         time_t sec;  
  7.   
  8.         sec = time(NULL);  
  9.   
  10.         printf("%ld\n", sec);  
  11.   
  12.         return 0;  
  13. }  
time函數返回自1970年1月1日凌晨以來的秒數,參數t可以爲NULL。同時還提供了一個函數difftime,原型如下:
double difftime(time_t time1, time_t time0);
用於比較兩個time_t類型的值。

2. struct tm
由time_t可以知道,操作系統使用的是long int類型的值來存儲時間,但對於用戶來說肯定是不好理解,所以就有了這裏的struct tm類型,定義如下:
struct tm {
    int tm_sec;         /* seconds */
    int tm_min;         /* minutes */
    int tm_hour;        /* hours */
    int tm_mday;        /* day of the month */
    int tm_mon;         /* month */
    int tm_year;        /* year */
    int tm_wday;        /* day of the week */
    int tm_yday;        /* day in the year */
    int tm_isdst;       /* daylight saving time */
};
-----------------------------------------------------------------
 tm_sec         |       秒,範圍是0~59。                        
 tm_min         |       分,範圍是0~59。                        
 tm_hour        |       時,範圍是0~23。                        
 tm_mday        |       日,範圍是1~31。                        
 tm_mon         |       月,範圍是0~11,注意是0到11。           
 tm_year        |       年,自1900以來的年數。                  
 tm_wday        |       星期幾,從星期天開始計算,範圍是0~6。
 tm_yday        |       一年中的哪一天,0~365。                 
 tm_isdst       |       夏令時間(DST)的一個標誌。             
-----------------------------------------------------------------

那怎麼能得到這個時間呢,有兩個函數gmtime和localtime,原型如下:
struct tm *gmtime(const time_t *timep);
struct tm *localtime(const time_t *timep);
例子如下:
  1. #include <stdio.h>  
  2. #include <time.h>  
  3.   
  4. int main(void)  
  5. {  
  6.         const char *const days[] = {"星期天""星期一""星期二",  
  7.                                 "星期三""星期四""星期五""星期六"};  
  8.         time_t sec;  
  9.   
  10.         struct tm *n;  
  11.   
  12.         sec = time(NULL);  
  13.   
  14.         n = localtime(&sec);  
  15.   
  16.         printf("%d年 %d月 %d日 %s %d:%d:%d\n",  
  17.                         n->tm_year + 1900,  
  18.                         n->tm_mon + 1,  
  19.                         n->tm_mday,  
  20.                         days[n->tm_wday],  
  21.                         n->tm_hour,  
  22.                         n->tm_min,  
  23.                         n->tm_sec);  
  24.   
  25.         return 0;  
  26. }  
那麼gmtime和localtime兩個函數有什麼不同的呢,gmtime獲取的是UTC時間,localtime獲取的是當前系統的時間。

再介紹兩個函數,ctime和asctime,原型如下:
char *ctime(const time_t *timep);
char *asctime(const struct tm *tm);
例子如下:
  1. #include <stdio.h>  
  2. #include <time.h>  
  3.   
  4. int main(void)  
  5. {  
  6.         time_t sec;  
  7.   
  8.         sec = time(NULL);  
  9.   
  10.         printf("%s\n", ctime(&sec));  
  11.   
  12.         return 0;  
  13. }  
上面程序執行結果如下:
Mon Nov 11 17:40:34 2013
也就說ctime函數將time_t類型的值轉換爲一個時間相關的字符串,而asctime同ctime函數不同的是,asctime的參數爲strut tm類型指針,而ctime的參數爲time_t類型的指針,只是參數類型不一樣,但是結果都是一樣的,都是獲取一個時間相關的字符串。

那既然有time函數將time_t值轉換爲struct tm類型值,那自然也有將struct tm類型值轉換爲time_t類型的值,函數爲mktime,原型爲:
time_t mktime(struct tm *tm);

3. 關於獲取和設置系統時鐘
前面使用的是time來獲取一個時間值,但是它的精度只能達到秒級,如果只是做一個日曆足夠了,但是如果想獲取更精確的時間呢,比如想計算程序的執行時間,顯然time函數不能滿足我們的要求,那就只能使用這裏的gettimeofday函數了,原型如下:
int gettimeofday(struct timeval *tv, struct timezone *tz);
其中struct timeval結構類型定義如下:
struct timeval {
	time_t      tv_sec;	/* seconds */
	suseconds_t tv_usec;	/* microseconds */
};
struct timeval結構類型提供了一個微秒級成員tv_usec,它的類型同樣是一個整型類型。
而gettimeofday函數的tz參數用於獲取時區信息,在Linux中通常設置爲NULL,程序例子如下:
  1. #include <stdio.h>  
  2. #include <sys/time.h>  
  3.   
  4. int main(void)  
  5. {  
  6.         struct timeval tv;  
  7.         int ret;  
  8.   
  9.         ret = gettimeofday(&tv, NULL);  
  10.         if (ret) {  
  11.                 perror("gettimeofday");  
  12.         } else {  
  13.                 printf("seconds=%ld useconds=%ld\n",  
  14.                         (long)tv.tv_sec, (long)tv.tv_usec);  
  15.         }  
  16.   
  17.         return 0;  
  18. }  
gettimeofday函數如果獲取失敗,返回-1值,同時設置errno爲EFAULT。

那如何去設置設置系統時鐘呢?這裏要介紹兩個函數,同time和gettimeofday對應,stime和settimeofday,原型如下:
int stime(time_t *t);
int settimeofday(const struct timeval *tv, const struct timezone *tz);
只是settimeofday設置的時間比stime更精確罷了。

4. 關於睡眠延時
睡眠延時先介紹兩個函數sleep和usleep,原型如下:
unsigned int sleep(unsigned int seconds);
int usleep(useconds_t usec);
sleep用於睡眠多少秒,而usleep爲睡眠多少微妙。
使用這兩個函數需要包含頭文件unistd.h。

5. 定時器
alarm函數原型如下:
unsigned alarm(unsigned seconds);
例子如下:
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <signal.h>  
  4.   
  5. void alarm_handler(int signum)  
  6. {  
  7.         printf("Five seconds passed!\n");  
  8. }  
  9.   
  10. void func(void)  
  11. {  
  12.         signal(SIGALRM, alarm_handler);  
  13.         alarm(5);  
  14.   
  15.         pause();  
  16. }  
  17.   
  18. int main(void)  
  19. {  
  20.         func();  
  21.   
  22.         return 0;  
  23. }  
程序將在5秒之後執行alarm_handler函數,這裏還使用了pause函數,用於掛起進程直到捕捉到一個信號時才退出。注意alarm一次只能發送發送一個信號,如果要再次發送信號,需要重新調用alarm函數。

除了alarm外,還可以使用setitimer來設置定時器,使用getitimer來獲取定時器的狀態,原型如下:
int setitimer(int which, const struct itimerval *restrict value,
              struct itimerval *restrict ovalue);
int getitimer(int which, struct itimerval *value);
需要包含頭文件sys/time.h

which參數有三種取值:
ITIMER_REAL	按實際時間記時,時間到了之後發送SIGALRM信號,相當於alarm。
ITIMER_VIRTUAL	僅當進程執行時才進行記時,發送SIGVTALRM信號。
ITIMER_PROF	當進程執行時和系統執行該進程時都記時,發送的是SIGPROF信號。

struct itimerval用來指定定時時間,定義如下:
struct itimerval {
	struct timerval it_interval;	/* next value */
	struct timerval it_value;	/* current value */
};
struct timeval結構前面都見過了,這裏就不再描述了。
在setitimer函數中,ovalue如果不爲空,則保留上次調用設置的值。例子如下:
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <signal.h>  
  4. #include <sys/time.h>  
  5.   
  6. void alarm_handler(int signo)  
  7. {  
  8.         printf("Timer hit!\n");  
  9. }  
  10.   
  11. void foo(void)  
  12. {  
  13.         struct itimerval delay;  
  14.         int ret;  
  15.   
  16.         signal(SIGALRM, alarm_handler);  
  17.   
  18.         delay.it_value.tv_sec = 1;  
  19.         delay.it_value.tv_usec = 0;  
  20.         delay.it_interval.tv_sec = 1;  
  21.         delay.it_interval.tv_usec = 0;  
  22.         ret = setitimer(ITIMER_REAL, &delay, NULL);  
  23.         if (ret) {  
  24.                 perror("setitimer");  
  25.                 return;  
  26.         }  
  27.   
  28.         while (1);  
  29. }  
  30.   
  31. int main(void)  
  32. {  
  33.         foo();  
  34.   
  35.         return 0;  
  36. }  
程序將每隔一秒鐘調用一次alarm_handler函數,注意這裏將delay.it_interval.tv_sec設置爲了1,當it_value中的值減到零時,將產生一個信號,並將it_value的值設置爲it_interval,然後又重新開始記時
發佈了14 篇原創文章 · 獲贊 8 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章