Linux/Unix time時間戳的處理轉換函數

linux下的時間函數

我們在編程中可能會經常用到時間,比如取得系統的時間(獲取系統的年、月、日、時、分、秒,星期等),或者是隔一段時間去做某事,那麼我們就用到一些時間函數。

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 tmtimeptr);
將結構中的信息轉換爲真實世界的時間,以字符串的形式顯示
char *ctime(const time_t *timep);
timep轉換爲真是世界的時間,以字符串顯示,它和asctime不同就在於傳入的參數形式不一樣
double difftime(time_t time1time_t time2);
返回兩個時間相差的秒數
int gettimeofday(struct timeval *tvstruct timezone *tz);
返回當前距離
1970年的秒數和微妙數,後面的tz是時區,一般不用
struct tmgmtime(const time_t *timep);
time_t表示的時間轉換爲沒有經過時區轉換的UTC時間,是一個struct tm結構指針
stuct tmlocaltime(const time_t *timep);
gmtime類似,但是它是經過時區轉換的時間。
time_t mktime(struct tmtimeptr);
struct tm 結構的時間轉換爲從1970年至今的秒數
time_t time(time_t *t)
取得從
197011日至今的秒數。

上面是簡單的介紹,下面通過實戰來看看這些函數的用法:

下載: 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
  1. /* gettime2.c*/
  2. #include <time.h>
  3. int main()
  4. {
  5. time_t timep;
  6. time(&timep)/*獲取time_t類型當前時間*/
  7. /*轉換爲常見的字符串:Fri Jan 11 17:04:08 2008*/
  8. printf("%s"ctime(&timep));
  9. return 0;
  10. }

編譯並運行:

$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
  1. /*gettime3.c */
  2. #include <time.h>
  3. int main()
  4. {
  5. char *wday[] = {"Sun""Mon""Tue""Wed""Thu""Fri""Sat"};
  6. time_t timep;
  7. struct tm *p;
  8. time(&timep)/*獲得time_t結構的時間,UTC時間*/
  9. p = gmtime(&timep)/*轉換爲struct tm結構的UTC時間*/
  10. printf("%d/%d/%d "1900 + p->tm_year1 + p->tm_monp->tm_mday);
  11. printf("%s %d:%d:%d/n"wday[p->tm_wday]p->tm_hour,
  12. p->tm_minp->tm_sec);
  13. return 0;
  14. }

編譯並運行:

$gcc -o gettime3 gettime3.c
$./gettime3
2008/1/11 Fri 17:42:54

從這個時間結果上來看,它和gettime1保持一致。

下載: gettime4.c
  1. /*gettime4.c*/
  2. #include <time.h>
  3. int main()
  4. {
  5. char *wday[] = {"Sun""Mon""Tue""Wed""Thu""Fri""Sat"};
  6. time_t timep;
  7. struct tm *p;
  8. time(&timep)/*獲得time_t結構的時間,UTC時間*/
  9. p = localtime(&timep)/*轉換爲struct tm結構的當地時間*/
  10. printf("%d/%d/%d "1900 + p->tm_year1 + p->tm_monp->tm_mday);
  11. printf("%s %d:%d:%d/n"wday[p->tm_wday]p->tm_hourp->tm_minp->tm_sec);
  12. return 0;
  13. }

編譯並運行:

$gcc -o gettime4 gettime4.c
$./gettime4
2008/1/12 Sat 1:49:29

從上面的結果我們可以這樣說:
time, gmtime, asctime 所表示的時間都是UTC時間,只是數據類型不一樣,而
localtime, ctime 所表示的時間都是經過時區轉換後的時間,它和你用系統命令date所表示的CST時間應該保持一致。

下載: gettime5.c
  1. /*gettime5.c*/
  2. #include <time.h>
  3. int main()
  4. {
  5. time_t timep;
  6. struct tm *p;
  7. time(&timep)/*當前time_t類型UTC時間*/
  8. printf("time():%d/n",timep);
  9. p = localtime(&timep)/*轉換爲本地的tm結構的時間按*/
  10. timep = mktime(p)/*重新轉換爲time_t類型的UTC時間,這裏有一個時區的轉換*/
  11. printf("time()->localtime()->mktime(): %d/n"timep);
  12. return 0;
  13. }

編譯並運行:

$gcc -o gettime5 gettime5.c
$./gettime5
time():1200074913
time()->localtime()->mktime(): 1200074913

這裏面把UTC時間按轉換爲本地時間,然後再把本地時間轉換爲UTC時間,它們轉換的結果保持一致。

下載: gettime6.c
  1. /*gettime6.c */
  2. #include <time.h>
  3. int main()
  4. {
  5. time_t timep;
  6. struct tm *p;
  7. time(&timep)/*得到time_t類型的UTC時間*/
  8. printf("time():%d/n",timep);
  9. p = gmtime(&timep)/*得到tm結構的UTC時間*/
  10. timep = mktime(p)/*轉換,這裏會有時區的轉換*/
  11. printf("time()->gmtime()->mktime(): %d/n"timep);
  12. return 0;
  13. }

編譯並運行:

$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 2008

clock: 取得進程佔用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: 0

gettimeofday: 取得目前的時間
頭文件: 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.

轉載地址:http://blog.csdn.net/cserchen/article/details/5954150

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章