我們在編程中可能會經常用到時間,比如取得系統的時間(獲取系統的年、月、日、時、分、秒,星期等 ),或者是隔一段時間去做某事,那麼我們就用到一些時間函數。
linux下存儲時間常見的有兩種存儲 方式,一個是從1970年到現在經過了多少秒,一個是用一個結構來分別存儲年月日時分秒的。
time_t 這種類型就是用來存儲從1970年到現在經過了多少秒,要想更精確一點,可以用結構struct timeval,它精確 到微妙。
struct timeval { long tv_sec ; /*秒*/ long tv_usec ; /*微秒*/ } ;
而直接存儲年月日的是一個結構:
struct tm { int tm_sec ; /*秒,正常范圍0-59, 但允許至61*/ int tm_min ; /*分鐘,0-59*/ int tm_hour ; /*小時, 0-23*/ int tm_mday ; /*日,即一個月中的第幾天,1-31*/ int tm_mon ; /*月, 從一月算起,0-11*/ int tm_year ; /*年, 從1900至今已經多少年*/ int tm_wday ; /*星期,一周中的第幾天, 從星期日算起,0-6*/ int tm_yday ; /*從今年1月1日到目前的天數,范圍0-365*/ int tm_isdst ; /*日光節約時間的旗標*/ } ;
需要特別注意的是,年份是從1900年起至今多少年,而不是直接存儲如2008年,月份從0開始的 ,0表示一月,星期也是從0開始的, 0表示星期日,1表示星期一。
下面介紹一下我們常用的時間函數 :
#include < time.h > char * asctime ( const struct tm * timeptr ) ; 將結構中的信息轉換為真實世界的時間,以字符串的形式顯示 char * ctime ( const time_t * timep ) ; 將 timep 轉換為真是世界的時間,以字符串顯示,它和 asctime 不同就在於傳入的參數形式不一樣 double difftime ( time_t time1 , time_t time2 ) ; 返回兩個時間相差的秒數 int gettimeofday ( struct timeval * tv , struct timezone * tz ) ; 返回當前距離 1970 年的秒數和微妙數,後 面的 tz 是 時區,一般不用 struct tm * gmtime ( const time_t * timep ) ; 將 time_t 表示的時間轉換為沒有 經過時區轉換的 UTC 時間,是一個 struct tm 結構指針 stuct tm * localtime ( const time_t * timep ) ; 和 gmtime 類似,但是它是經過時 區轉換的時間。 time_t mktime ( struct tm * timeptr ) ; 將 struct tm 結構的時間轉換為從 1970 年至今的秒數 time_t time ( time_t * t ) ; 取得從 1970 年 1 月 1 日至今的秒數。
上面是簡單的介紹,下面通過實戰來看看這些函數的用法 :
/*gettime1.c*/ #include < time.h > int main () { time_t timep ; time ( & timep ) ; /*獲取time_t類型的當 前時間*/ /*用gmtime將time_t類型的時間轉換為struct tm類型的時間按, 然後再用asctime轉換為我們常見的格式 Fri Jan 11 17:25:24 2008 */ printf ( " %s " , asctime ( gmtime ( & timep ))) ; return 0 ; }
編譯並運行:
$gcc -o gettime1 gettime1.c
$./gettime1
Fri Jan 11 17:04:08 2008
下面是直接把time_t類型的轉換為我們常見的格式:
/* gettime2.c*/ #include < time.h > int main () { time_t timep ; time ( & timep ) ; /*獲取time_t類型當前 時間*/ /*轉換為常見的字符 串:Fri Jan 11 17:04:08 2008*/ printf ( " %s " , ctime ( & timep )) ; return 0 ; }
編譯並運行:
$gcc -o gettime2 gettime2.c
$./gettime2
Sat Jan 12 01:25:29 2008
我看了一本書上面說的這兩個例子如果先後執行的話,兩個的結果除了秒上有差別之外(執行程 序需要時間),應該是一樣的,可是我這裡執行卻發現差了很長時間按,一個是周五,一個是周六,後來我用 date 命令執行了一遍
$date
六 1月 12 01:25:19 CST 2008
我發現date和gettime2比 較一致, 我估計可能gettime1並沒有經過時區的轉換,它們是有差別的。
/*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結構的時 間,UTC時間*/ p = gmtime ( & timep ) ; /*轉換為struct tm結構的UTC時間*/ 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 ; }
編譯並運行:
$gcc -o gettime3 gettime3.c
$./gettime3
2008/1/11 Fri 17:42:54
從這個時間結果上來看,它和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結構的時 間,UTC時間*/ p = localtime ( & timep ) ; /*轉換為struct tm結構的當地時間*/ 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 ; }
編譯並運行:
$gcc -o gettime4 gettime4.c
$./gettime4
2008/1/12 Sat 1:49:29
從上面的結果我們可以這樣說:
time, gmtime, asctime 所表示的時間都是UTC時間,只是 數據類型不一樣,而
localtime, ctime 所表示的時間都是經過時區轉換後的時間,它和你用系統命令date 所表示的CST時間應該保持一致。
/*gettime5.c*/ #include < time.h > int main () { time_t timep ; struct tm * p ; time ( & timep ) ; /*當前time_t類型 UTC時間*/ printf ( " time():%d / n " , timep ) ; p = localtime ( & timep ) ; /*轉換為本地的tm結構的時間按*/ timep = mktime ( p ) ; /*重新轉換為time_t類型的UTC時間,這裡有一個時區的轉換*/ printf ( " time()->localtime()->mktime(): %d / n " , timep ) ; return 0 ; }
編譯並運行:
$gcc -o gettime5 gettime5.c
$./gettime5
time ():1200074913
time()->localtime()->mktime(): 1200074913
這裡面把UTC時間按轉換為本 地時間,然後再把本地時間轉換為UTC時間,它們轉換的結果保持一致。
/*gettime6.c */ #include < time.h > int main () { time_t timep ; struct tm * p ; time ( & timep ) ; /*得到time_t類型的 UTC時間*/ printf ( " time():%d / n " , timep ) ; p = gmtime ( & timep ) ; /*得到tm結構的UTC時間*/ timep = mktime ( p ) ; /*轉換,這裡會有時區的轉換*/ printf ( " time()->gmtime()->mktime(): %d / n " , timep ) ; return 0 ; }
編譯並運行:
$gcc -o gettime6 gettime6.c
$./gettime6
time ():1200075192
time()->gmtime()->mktime(): 1200046392
從這裡面我們可以看出,轉換後 時間不一致了,計算一下,整整差了8個小時( (1200075192-1200046392)/3600 = 8),說明mktime會把本地時 間轉換為UTC時間,這裡面本來就是UTC時間,於是再弄個時區轉換,結果差了8個小時,用的時候應該注意。