LinuxUnix time時間戳的處理轉換函式
我們在程式設計中可能會經常用到時間,比如取得系統的時間(獲取系統的年、月、日、時、分、秒,星期等),或者是隔一段時間去做某事,那麼我們就用到一些時間函式。
linux下儲存時間常見的有兩種儲存方式:
一個是從1970年到現在經過了多少秒;
一個是用一個結構來分別儲存年月日時分秒的。
time_t 這種型別就是用來儲存從1970年到現在經過了多少秒,要想更精確一點,可以用結構struct timeval,它精確到微妙。
1 struct timeval
2 {
3 long tv_sec; /*秒*/
4 long tv_usec; /*微秒*/
5 };
而直接儲存年月日的是一個結構:1 struct tm 2 { 3 int tm_sec; /*秒,正常範圍0-59, 但允許至61*/ 4 int tm_min; /*分鐘,0-59*/ 5 int tm_hour; /*小時, 0-23*/ 6 int tm_mday; /*日,即一個月中的第幾天,1-31*/ 7 int tm_mon; /*月, 從一月算起,0-11*/ 8 int tm_year; /*年, 從1900至今已經多少年*/ 9 int tm_wday; /*星期,一週中的第幾天, 從星期日算起,0-6*/ 10 int tm_yday; /*從今年1月1日到目前的天數,範圍0-365*/ 11 int tm_isdst; /*日光節約時間的旗標*/ 12 };
需要特別注意的是,年份是從1900年起至今多少年,而不是直接儲存如2008年,月份從0開始的,0表示一月,星期也是從0開始的, 0表示星期日,1表示星期一。
下面介紹一下我們常用的時間函式:
上面是簡單的介紹,下面通過實戰來看看這些函式的用法:1 #include <time.h> 2 3 char *asctime(const struct tm* timeptr); //將結構中的資訊轉換為真實世界的時間,以字串的形式顯示; 4 5 char *ctime(const time_t *timep); //將timep轉換為真是世界的時間,以字串顯示,它和asctime不同就在於傳入的引數形式不一樣; 6 7 double difftime(time_t time1, time_t time2); //返回兩個時間相差的秒數; 8 9 int gettimeofday(struct timeval *tv, struct timezone *tz); //返回當前距離1970年的秒數和微妙數,後面的tz是時區,一般不用; 10 11 struct tm* gmtime(const time_t *timep); //將time_t表示的時間轉換為沒有經過時區轉換的UTC時間,是一個struct tm結構指標; 12 13 stuct tm* localtime(const time_t *timep); //和gmtime類似,但是它是經過時區轉換的時間。 14 15 time_t mktime(struct tm* timeptr); //將struct tm 結構的時間轉換為從1970年至今的秒數; 16 17 time_t time(time_t *t); //取得從1970年1月1日至今的秒數。
下載: gettime1.c
1 /*gettime1.c*/
2 #include <time.h>
3 int main()
4 {
5 time_t timep;
6 time(&timep); /*獲取time_t型別的當前時間*/
7 /*用gmtime將time_t型別的時間轉換為struct tm型別的時間按,
8 然後再用asctime轉換為我們常見的格式 Fri Jan 11 17:25:24 2008
9 */
10 printf("%s", asctime(gmtime(&timep)));
11 return 0;
12 }
編譯並執行:
$gcc -o gettime1 gettime1.c
$./gettime1
Fri Jan 11 17:04:08 2008
下面是直接把time_t型別的轉換為我們常見的格式:下載: gettime2.c
13 /* gettime2.c*/
14 #include <time.h>
15 int main()
16 {
17 time_t timep;
18 time(&timep); /*獲取time_t型別當前時間*/
19 /*轉換為常見的字串:Fri Jan 11 17:04:08 2008*/
20 printf("%s", ctime(&timep));
21 return 0;
22 }
編譯並執行:
$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
23 /*gettime3.c */
24 #include <time.h>
25 int main()
26 {
27 char *wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
28 time_t timep;
29 struct tm *p;
30 time(&timep); /*獲得time_t結構的時間,UTC時間*/
31 p = gmtime(&timep); /*轉換為struct tm結構的UTC時間*/
32 printf("%d/%d/%d ", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday);
33 printf("%s %d:%d:%d/n", wday[p->tm_wday], p->tm_hour,
34 p->tm_min, p->tm_sec);
35 return 0;
36 }
編譯並執行:
$gcc -o gettime3 gettime3.c
$./gettime3
2008/1/11 Fri 17:42:54
從這個時間結果上來看,它和gettime1保持一致。
下載: gettime4.c
37 /*gettime4.c*/
38 #include <time.h>
39 int main()
40 {
41 char *wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
42 time_t timep;
43 struct tm *p;
44 time(&timep); /*獲得time_t結構的時間,UTC時間*/
45 p = localtime(&timep); /*轉換為struct tm結構的當地時間*/
46 printf("%d/%d/%d ", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday);
47 printf("%s %d:%d:%d/n", wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);
48 return 0;
49 }
編譯並執行:
$gcc -o gettime4 gettime4.c
$./gettime4
2008/1/12 Sat 1:49:29
從上面的結果我們可以這樣說:time, gmtime, asctime 所表示的時間都是UTC時間,只是資料型別不一樣,而
localtime, ctime 所表示的時間都是經過時區轉換後的時間,它和你用系統命令date所表示的CST時間應該保持一致。
下載: gettime5.c
50 /*gettime5.c*/ 51 #include <time.h> 52 int main() 53 { 54 time_t timep; 55 struct tm *p; 56 time(&timep); /*當前time_t型別UTC時間*/ 57 printf("time():%d/n",timep); 58 p = localtime(&timep); /*轉換為本地的tm結構的時間按*/ 59 timep = mktime(p); /*重新轉換為time_t型別的UTC時間,這裡有一個時區的轉換*/ 60 printf("time()->localtime()->mktime(): %d/n", timep); 61 return 0; 62 } 編譯並執行: $gcc -o gettime5 gettime5.c $./gettime5 time():1200074913 time()->localtime()->mktime(): 1200074913這裡面把UTC時間按轉換為本地時間,然後再把本地時間轉換為UTC時間,它們轉換的結果保持一致。
下載: gettime6.c
63 /*gettime6.c */ 64 #include <time.h> 65 int main() 66 { 67 time_t timep; 68 struct tm *p; 69 time(&timep); /*得到time_t型別的UTC時間*/ 70 printf("time():%d/n",timep); 71 p = gmtime(&timep); /*得到tm結構的UTC時間*/ 72 timep = mktime(p); /*轉換,這裡會有時區的轉換*/ 73 printf("time()->gmtime()->mktime(): %d/n", timep); 74 return 0; 75 } 編譯並執行: $gcc -o gettime6 gettime6.c $./gettime6 time():1200075192 time()->gmtime()->mktime(): 1200046392
從這裡面我們可以看出,轉換後時間不一致了,計算一下,整整差了8個小時( (1200075192-1200046392)/3600 = 8 ),說明mktime會把本地時間轉換為UTC時間,這裡面本來就是UTC時間,於是再弄個時區轉換,結果差了8個小時,用的時候應該注意。
函式分類:
1. 設定時間: settimeofday, tzset
2. 獲取時間: time, ftime, gettimeofday
3. 時間格式轉換: mktime, strftime; gmtime, localtime; asctime, ctime
4. 其他: clock, difftime
asctime: 將時間和日期以字串格式表示
標頭檔案: time.h
函式定義: char *asctime(const struct tm *timeptr);
說明: asctime()將函式timeptr所指的tm結構中的資訊轉換成現實世界所使用的時間日期表示方法, 然後將結果以字串形態返回. 此函式已經由時區轉換成當地時間, 返回的字串格式為: "Wed Jun 30 21:49:08 1993/n"
ctime: 將時間和日期以字串格式表示
標頭檔案: time.h
函式定義: char *ctime(const time_t *timep);
說明: ctime()同asctime()函式, 只是輸入引數為time_t.
應用舉例:
#include <stdio.h> #include <time.h> int main(void) { time_t timep; time(&timep); printf("%s", ctime(&timep)); printf("%s", asctime(gmtime(&timep))); return 0; } 執行結果: Sun Dec 14 15:30:11 2008 Sun Dec 14 15:30:11 2008clock: 取得程序佔用CPU的大約時間
標頭檔案: time.h
函式定義: clock_t clock(void);
說明: clock()用來返回程序所佔用CPU的大約時間.
difftime: 計算時間差距
標頭檔案: time.h
函式定義: double difftime(time_t time1, time_t time0);
說明: difftime()用來計算引數time1-time0, 結果以double型精確值返回. 兩個引數的時間都是以1970年1月1日0時0分0秒算起的UTC時間.
ftime: 取得目前的時間和日期
標頭檔案: sys/timeb.h
函式定義: int ftime(struct timeb *tp);
說明: ftime()將日前時間日期由引數tp所指的結構輸出. tp結構定義如下:
struct timeb{
/* 為從1970年1月1日至今的秒數 */
time_t time;
/* 為千分之一秒 */
unsigned short millitm;
/* 為目前時區和Greenwich相差的時間, 單位為單位 */
short timezone;
/* 為日光節約時間的修正狀態, 若非0為啟用日光節約時間的修正 */
short dstflag;
};
無論成功還是失敗都返回0.
應用舉例:
#include <stdio.h> #include <sys/timeb.h> int main(void) { struct timeb tp; ftime(&tp); printf("time: %d/n", tp.time); printf("millitm: %d/n", tp.millitm); printf("timezone: %d/n", tp.timezone); printf("dstflag: %d/n", tp.dstflag); return 0; } 執行結果: time: 1229271908 millitm: 716 timezone: -480 dstflag: 0gettimeofday: 取得目前的時間
標頭檔案: sys/time.h unist.d
函式定義: int gettimeofday(struct timeval *tv, struct timezone *tz);
說明: gettimeofday()會把目前的時間用tv所指的結構返回, 當地時區的資訊則放到tz所指的結構中. 成功則返回0, 失敗返回-1, 錯誤程式碼存於errno. EFAULT是指標tv和tz所指的記憶體空間超出存取許可權.
timeval結構定義為:
struct timeval{ /* 為從1970年1月1日至今的秒數 */ long tv_sec; /* 微秒 */ long tv_usec; }; timezone 結構定義為: struct timezone{ /* 和Greenwich時間差了多少分鐘 */ int tz_minuteswest; /*日光節約時間的狀態*/ int tz_dsttime; }; 上述兩個結構都定義在/usr/include/sys/time.h, tz_dsttime所代表的狀態如下: DST_NONE /*不使用*/ DST_USA /*美國*/ DST_AUST /*澳洲*/ DST_WET /*西歐*/ DST_MET /*中歐*/ DST_EET /*東歐*/ DST_CAN /*加拿大*/ DST_GB /*大不列顛*/ DST_RUM /*羅馬尼亞*/ DST_TUR /*土耳其*/ DST_AUSTALT /*澳洲(1986年以後)*/
gmtime: 將秒數轉換目前的時間和日期
標頭檔案: time.h
函式定義: struct tm *gmtime(const time_t *timep);
說明: gmtime()將引數timep所指的time_t結構中的資訊轉換成現實世界所使用的時間日期表示方法, 然後將結果由結構tm返回.
結構tm的定義為:
struct tm{ int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; }; 引數說明: int tm_sec 代表目前秒數, 正常範圍為0-59, 但允許至61秒 int tm_min 代表目前分數, 範圍0-59 int tm_hour 從午夜算起的時數, 範圍為0-23 int tm_mday 目前月份的日數, 範圍01-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 日光節約時間的旗標
此函式返回的時間日期未經時區轉換, 是UTC時間.
localtime: 將秒數轉換當地目前的時間和日期
標頭檔案: time.h
函式定義: struct *localtime(const time_t *timep);
說明: localtime()將引數timep所指的time_t結構中的資訊轉換成真實世界所使用的時間日期表示方法, 然後將結果由結構tm返回. 結構tm的定義請參考gmtime(). 此函式返回的時間日期已經轉換成當地時區.
mktime: 將時間結構資料轉換成經過的秒數
標頭檔案: time.h
函式定義: time_t mktime(struct tm *timeptr);
說明: mktime()用來將引數timeptr所指的tm結構資料轉換成從1970年1月1日0時0分0秒算起至今的UTC時間所經過的秒數. 返回經過的秒數.
settimeofday: 設定目前的時間
標頭檔案: sys/time.h unistd.h
函式定義: settimeofday()會把目前時間設成由tv所指的結構資訊, 當地時區資訊則設成tz所指的結構. 詳細的說明請參考gettimeofday(). 注意, 只有root許可權才能使用此函式修改時間. 成功則返回0, 失敗返回-1, 錯誤程式碼存於errno.
錯誤程式碼:
EPERM 並非由root許可權呼叫settimeofday(), 許可權不夠
EINVAL 時區或某個資料是不正確的, 無法正確設定時間
strftime: 格式化日期和時間
標頭檔案: time.h
函式定義: size_t strftime(char *s, size_t max, const char *format, const struct tm *tm);
說明: strftime()會將引數tm的時間結構, 參照引數format所指定的字串格式做轉換, 轉換後的字串內容將複製到引數s所指的字串陣列中, 該字串的最大長度為引數max所控制.
下面是引數format的格式指令:
%a 當地星期日期的名稱縮寫, 如: Sun
%A 當地星期日期的名稱縮寫, 如: Sunday
%b 當地月份的縮寫
%B 當地月份的完整名稱
%c 當地適當的日期與時間表示法
%C 以year/100表示年份
%d 月裡的天數, 表示法為01-31
%D 相當於"%m%d%y"格式
%e 月裡的天數, 表示法為1-31
%h 當地月份的縮寫
%H 以24小時製表示小時數, 表示法為00-23
%I 以12小時製表示小時數, 表示法為01-12
%j 一年中的天數(001-366)
%k 以24小時製表示小時數, 表示法為0-23
%l 以12小時製表示小時數, 表示法為1-12
%m 月份(01-12)
%M 分鐘數(00-59)
%n 同/n
%p 顯示對應的AM或PM
%P 顯示對應的am或pm
%r 相當於使用"%I:%M:%S %p"格式
%R 相當於使用"%H:%M"格式
%s 從1970年1月1日0時0分0秒算起至今的UTC時間所經過的秒數
%S 秒數(00-59)
%t 同/t
%T 24小時時間表示, 相當於"%H:%M:%S"格式
%u 一星期中的星期日期, 範圍1-7, 星期一從1開始
%U 一年中的星期數(00-53), 一月第一個星期日開始為01
%w 一星期中的星期日期, 範圍0-6, 星期日從0開始
%W 一年中的星期數(00-53), 一月第一個星期一開始為01
%x 當地適當的日期表示
%X 當地適當的時間表示
%y 一世紀中的年份表示
%Y 完整的公元年份表示
%Z 使用的時區名稱
%% '%'符號
返回複製到引數s所指的字串陣列的總字元數, 不包括字串結束符. 如果返回0, 表示未複製字串到引數s內, 但不表示一定有錯誤發生.
附加說明: 環境變數TZ和TC_TIME會影響此函式結果.
應用舉例:
#include <stdio.h> #include <time.h> int main(void) { char *format[] = {"%I: %M: %S %p %m/%d %a", "%x %X %Y", NULL}; char buf[30]; int i; time_t clock; struct tm *tm; time(&clock); tm = localtime(&clock); for(i = 0; format[i] != NULL; i++) { strftime(buf, sizeof(buf), format[i], tm); printf("%s => %s/n", format[i], buf); } return 0; } 執行結果: %I: %M: %S %p %m/%d %a => 01: 46: 44 AM 12/15 Mon %x %X %Y => 12/15/08 01:46:44 2008
time: 取得目前的時間
標頭檔案: time.h
函式定義: time_t time(time_t *t);
說明: time()會返回從1970年1月1日從0時0分0秒算起的UTC時間到現在所經過的秒數. 如果t並非空指標的話, 此函式也會將返回值存到t指標所指的記憶體. 成功則返回秒數, 失敗則返回(time_t-1)值, 錯誤原因存於errno中.
tzset: 設定時區以供時間轉換
標頭檔案: time.h
函式定義: void tzset(void); extern char *tzname[2];
說明: tzset()用來將環境變數TZ設給全域性變數tzname, 也就是從環境變數取得目前當地的時區. 時間轉換函式會自動呼叫此函式. 若TZ為設定, tzname會依照/etc/localtime找出最接近當地的時區. 若TZ為NULL, 或是無法判認, 則使用UTC時區. 此函式總是成功, 並且初始化tzname.