UNIX操作系統根據計算機產生的年代和應用采用1970年1月1日作為UNIX的紀元時間,1970年1月1日0點作為計算機表示時間的是中間點,將從1970年1月1日開始經過的秒數用一個整數存放,這種高效簡潔的時間表示方法被稱為“Unix時間紀元”,向左和向右偏移都可以得到更早或者更后的時間。
在實際開發中,對日期和時間的操作場景非常多,例如程序啟動和退出的時間,程序執行任務的時間,數據生成的時間,數據處理的各環節的時間等,無處不在。
在學習時間之前,請把Linux操作系統的時區設置為中國上海時間。
一、time_t別名
在C語言中,用time_t來表示時間數據類型,它是一個long(長整數)類型的別名,在time.h文件中定義,表示一個日歷時間,是從1970年1月1日0時0分0秒到現在的秒數。
typedef long time_t;
二、time庫函數
time函數的用途是返回一個值,也就是從1970年1月1日0時0分0秒到現在的秒數。
time函數是C語言標准庫中的函數,在time.h文件中聲明。
time_t time(time_t *t);
time函數有兩種調用方法:
time_t tnow;
tnow =time(0); // 將空地址傳遞給time函數,並將time返回值賦給變量tnow
或
time(&tnow); // 將變量tnow的地址作為參數傳遞給time函數
您可以寫代碼測試一下這兩種方式,效果完全相同。
三、tm結構體
time_t只是一個長整型,不符合我們的使用習慣,需要轉換成可以方便表示時間的結構體,即tm結構體,tm結構體在time.h中聲明,如下:
struct tm
{
int tm_sec; // 秒:取值區間為[0,59]
int tm_min; // 分:取值區間為[0,59]
int tm_hour; // 時:取值區間為[0,23]
int tm_mday; // 日期:一個月中的日期:取值區間為[1,31]
int tm_mon; // 月份:(從一月開始,0代表一月),取值區間為[0,11]
int tm_year; // 年份:其值等於實際年份減去1900
int tm_wday; // 星期:取值區間為[0,6],其中0代表星期天,1代表星期一,以此類推
int tm_yday; // 從每年的1月1日開始的天數:取值區間為[0,365],其中0代表1月1日,1代表1月2日,以此類推
int tm_isdst; // 夏令時標識符,該字段意義不大,我們不用夏令時。
};
這個結構定義了年、月、日、時、分、秒、星期、當年中的某一天、夏令時。用這個結構體可以很方便的顯示時間。
四、localtime庫函數
localtime函數用於把time_t表示的時間轉換為struct tm結構體表示的時間,函數返回struct tm結構體的地址。
函數聲明:
struct tm * localtime(const time_t *);
struct tm結構體包含了時間的各要素,但還不是我們習慣的時間表達方式,我們可以用格式化輸出printf、sprintf或fprintf等函數,把struct tm結構體轉換為我們想要的結果。
示例(book128.c)
/*
* 程序名:book128.c,此程序演示獲取操作系統時間
* 作者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <time.h>
int main(int argc,char *argv[])
{
time_t tnow;
tnow=time(0); // 獲取當前時間
printf("tnow=%lu\n",tnow); // 輸出整數表示的時間
struct tm *sttm;
sttm=localtime(&tnow); // 把整數的時間轉換為struct tm結構體的時間
// yyyy-mm-dd hh24:mi:ss格式輸出,此格式用得最多
printf("%04u-%02u-%02u %02u:%02u:%02u\n",sttm->tm_year+1900,sttm->tm_mon+1,\
sttm->tm_mday,sttm->tm_hour,sttm->tm_min,sttm->tm_sec);
printf("%04u年%02u月%02u日%02u時%02u分%02u秒\n",sttm->tm_year+1900,\
sttm->tm_mon+1,sttm->tm_mday,sttm->tm_hour,sttm->tm_min,sttm->tm_sec);
// 只輸出年月日
printf("%04u-%02u-%02u\n",sttm->tm_year+1900,sttm->tm_mon+1,sttm->tm_mday);
}
運行效果

五、mktime庫函數
mktime函數的功能與localtime函數相反。
localtime函數用於把time_t表示的時間轉換為struct tm表示的時間。
mktime 函數用於把struct tm表示的時間轉換為time_t表示的時間。
time_t mktime(struct tm *tm);
函數返回time_t的值。
示例(book130.c)
/*
* 程序名:book130.c,此程序演示時間操作的mktime庫函數。
* 作者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <time.h>
#include <string.h>
int main(int argc,char *argv[])
{
// 2019-12-25 15:05:03整數表示是1577257503
struct tm sttm;
memset(&sttm,0,sizeof(sttm));
sttm.tm_year=2019-1900; // 注意,要減1900
sttm.tm_mon=12-1; // 注意,要減1
sttm.tm_mday=25;
sttm.tm_hour=15;
sttm.tm_min=5;
sttm.tm_sec=3;
sttm.tm_isdst = 0;
printf("2019-12-25 15:05:03 is %lu\n",mktime(&sttm));
}
運行效果

六、程序睡眠
在實際開發中,我們經常需要把程序掛起一段時間,可以使用sleep和usleep兩個庫函數,需要包含unistd.h頭文件中。函數的聲明如下:
unsigned int sleep(unsigned int seconds);
int usleep(useconds_t usec);
sleep函數的參數是秒,usleep函數的參數是微秒,1秒=1000000微秒。
sleep(1); // 程序睡眠1秒。
sleep(10); // 程序睡眠10秒。
usleep(100000); // 程序睡眠十分之一秒。
usleep(1000000); // 程序睡眠一秒。
程序員不關心sleep和usleep函數的返回值。
七、精確到微秒的計時器
1、精確到微秒的timeval結構體
timeval結構體在sys/time.h文件中定義,聲明為:
struct timeval
{
long tv_sec; // 1970年1月1日到現在的秒。
long tv_usec; // 當前秒的微妙,即百萬分之一秒。
};
2、時區timezone 結構體
timezone 結構體在sys/time.h文件中定義,聲明為:
struct timezone
{
int tz_minuteswest; // 和UTC(格林威治時間)差了多少分鍾。
int tz_dsttime; // type of DST correction,修正參數據,忽略
};
3、gettimeofday庫函數
gettimeofday是獲得當前的秒和微秒的時間,其中的秒是指1970年1月1日到現在的秒,微秒是指當前秒已逝去的微秒數,可以用於程序的計時。調用gettimeofday函數需要包含sys/time.h頭文件。
函數聲明:
int gettimeofday(struct timeval *tv, struct timezone *tz )
當前的時間存放在tv 結構體中,當地時區的信息則放到tz所指的結構體中,tz可以為空。
函數執行成功后返回0,失敗后返回-1。
在使用gettimeofday()函數時,第二個參數一般都為空,我們一般都只是為了獲得當前時間,不關心時區的信息。
示例(book132.c)
/*
* 程序名:book132.c,此程序演示精確到微秒的計時器。
* 作者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <sys/time.h> // 注意,不是time.h
int main()
{
struct timeval begin,end; // 定義用於存放開始和結束的時間
gettimeofday(&begin,0); // 計時器開始
printf("begin time(0)=%d,tv_sec=%d,tv_usec=%d\n",time(0),begin.tv_sec,begin.tv_usec);
sleep(2);
usleep(100000); // 程序睡眠十分之一秒。
gettimeofday(&end,0); // 計時器結束
printf("end time(0)=%d,tv_sec=%d,tv_usec=%d\n",time(0),end.tv_sec,end.tv_usec);
printf("計時過去了%d微秒。\n",\
(end.tv_sec-begin.tv_sec)*1000000+(end.tv_usec-begin.tv_usec));
}
運行效果

各位,book132.c程序采用usleep睡眠十分之一秒,但是計時器顯示的實際時間大於十分之一秒,為何?原因很簡單,因為程序執行需要時間,雖然這個時間很短,在千分之一秒內,那也是需要時間。
還有一個要注意的問題,time.h 是ISO C99 標准日期時間頭文件。sys/time.h 是Linux系統的日期時間頭文件,也就是說,timeval、timezone結構體和gettimeofday函數在windows平台中不能使用,真是麻煩。
八、應用經驗
在實際開發中,除了當前的時間,還經常需要一個偏移量的時間,例如獲取十分鍾之后的時間,方法是采用time函數得到一個整數后,再加上10*60秒,再用localtime函數轉換為結構體。
九、課后作業
繼續豐富您的函數庫。
1)編寫一個通用函數,把整數的時間轉換為字符串格式的時間,格式如:"2019-02-08
12:05:08",如果轉換成功函數返回0,失敗返回-1,函數的聲明如下:
int timetostr(const time_t ti,char *strtime);
2)編寫一個通用函數,把字符串格式的時間轉換為整數的時間,函數的聲明如下:
int strtotime(const char *strtime,time_t *ti);
3)編寫一個通用函數,獲取操作系統的時間,函數的聲明如下:
void LocalTime(char *out_stime,const char *in_fmt,const int in_interval);
out_stime是輸出結果,格式由fmt決定。
in_interval是偏移常量,單位是秒。
in_fmt指定了out_stime的格式,取值如下:
/* 常用的時間格式
yyyy-mm-dd hh24:mi:ss
yyyymmddhh24miss
yyyy-mm-dd
yyyymmdd
hh24:mi:ss
hh24miss
hh24:mi
hh24mi
hh24
mi
*/
調用示例:
char strLocalTime[21];
// 獲取當前的時間,以yyyy-mm-dd hh24:mi:ss格式返回
memset(strLocalTime,0,sizeof(strLocalTime));
LocalTime(strLocalTime,"yyyy-mm-dd hh24:mi:ss",0);
// 獲取比現在晚10分鍾的時間,以yyyy-mm-dd hh24:mi:ss格式返回
memset(strLocalTime,0,sizeof(strLocalTime));
LocalTime(strLocalTime,"yyyy-mm-dd hh24:mi:ss",10*60);
// 獲取當前的時間,以hh24:mi:ss格式返回
memset(strLocalTime,0,sizeof(strLocalTime));
LocalTime(strLocalTime,"hh24:mi:ss",0);
十、版權聲明
C語言技術網原創文章,轉載請說明文章的來源、作者和原文的鏈接。
來源:C語言技術網(www.freecplus.net)
作者:碼農有道
如果文章有錯別字,或者內容有錯誤,或其他的建議和意見,請您留言指正,非常感謝!!!
