一、時區相關概念
地球自西往東轉動,東邊比西邊先看到太陽,所以東邊的時間比西邊的時間早。將地球經度按照24個時區進行劃分,每個時區相隔的經度爲15度。以英國倫敦(格林尼治天文臺舊址)爲中時區(零時區),向東有11個時區,向西也有11個時區,太平洋白令海峽所在經度爲12區,東西各佔一半。0時區向東每隔一個時區時間快1小時,向西每隔一個時區時間慢1小時。在12區中間,左邊剛好比右邊日期大1天。
UTC協調時間時間=世界標準時間=格林尼治時間=G.M.T(Greenwich Mean Time),指0時區所處的時間。
夏令時(陽光節約時/DST/Daylight Saving Time):因爲北半球大部分國家在夏天日照時間較長,爲了節約能源,讓人們充分利用太陽光源,某些國家在夏天會人爲地將時間設置快一個小時。例如美國每年3月的第二個星期日開始,至每年11月的第一個星期日爲夏令時。
二、計算機時間
1970-01-01 00:00:00是計算機元年,因爲Unix操作系統和C語言於1971年發佈,所以將這一時間作爲時間元年。
三、C庫時間操作函數
1、time
函數原型:time_t time(time_t* timer);
函數說明:獲取系統UTC時間到1970-01-01 00:00:00的秒數。timer爲NULL,通過返回值返回。也可以通過timer參數返回。time_t在32位系統下最大隻能表示到2038-01-19 03:14:07,在64位系統下則完全夠用
2、localtime
函數原型:struct tm* localtime(const timer_t* timer);
tm結構:
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 到 11 */
int tm_year; /* 自 1900 年起的年數 */
int tm_wday; /* 一週中的第幾天,範圍從 0 到 6 */
int tm_yday; /* 一年中的第幾天,範圍從 0 到 365 */
int tm_isdst; /* 夏令時 */
};
函數說明:將time_t類型值轉換爲tm結構,採用本地時區
線程安全:locltime爲非線程安全函數,返回的爲內部靜態變量指針,linux下線程安全函數爲localtime_r(),windows下沒有
3、gmtime
函數原型:struct tm* gmtime(time_t* timer);
函數說明:將time_t類型值轉換爲tm結構,採用0時區
線程安全:linux下線程安全函數爲gmtime_r()
4、mktime
函數原型:time_t mktime(struct tm* timeptr);
函數說明:計算將timeptr按照系統時區轉換爲0時區,然後到計算機元年間的秒數
例子:
#include <time.h>
#include <stdio.h>
int main()
{
time_t t = time(NULL);
//or
//time_t t;
//time(&t);
struct tm* tmLocalNow = localtime(&t);
tmLocalNow->tm_year += 1900;
tmLocalNow->tm_mon += 1;
printf("local now datetime: %d.%02d.%02d %02d:%02d:%02d\n",
tmLocalNow->tm_year,tmLocalNow->tm_mon,tmLocalNow->tm_mday,tmLocalNow->tm_hour,tmLocalNow->tm_min,tmLocalNow->tm_sec);
struct tm* tmUTCNow = gmtime(&t);
tmUTCNow->tm_year += 1900;
tmUTCNow->tm_mon += 1;
printf("UTC now datetime: %d.%02d.%02d %02d:%02d:%02d\n",
tmUTCNow->tm_year,tmUTCNow->tm_mon,tmUTCNow->tm_mday,tmUTCNow->tm_hour,tmUTCNow->tm_min,tmUTCNow->tm_sec);
return 0;
}
線程不安全例子:
#include <time.h>
#include <stdio.h>
int main()
{
time_t t1 = time(NULL);
time_t t2 += 1800;
struct tm* tm1 = localtime(&t1);
struct tm* tm2 = localtime(&t2);
//執行到這裏的時候tm1值變爲tm2,因爲內部他們指向的是同一內存地址
return 0;
}
5、Sleep/sleep/usleep
Sleep(毫秒)爲windows下掛起函數,精確到毫秒級
sleep(秒)爲linux下掛起函數,精確到秒級。
usleep(微秒)爲linux下掛起函數,精確到微秒級。
Sleep()在windows下掛起後仍然會佔用CPU處理時間,而sleep()和usleep()在linux下不會佔用
6、clock
函數原型:clock_t clock();
函數說明,返回從程序執行時起到現在,消耗的處理器時間(不是程序執行時間)對應的時鐘數,每秒鐘處理器的時鐘數爲CLOCKS_PER_SEC。
例子:
#ifdef WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <time.h>
int main()
{
clock_t clockStart;
clockStart = clock();
#ifdef WIN32
Sleep(2000);
#else
sleep(2);
#endif
clock_t clockEnd;
clockEnd = clock();
double dInterval = (double)(clockEnd - clockStart) / CLOCKS_PER_SEC;
printf("interval: %f\n", dInterval);
}
執行結果:
linux下爲0.000040,windows下爲2.001000,因爲linux下sleep()不佔用CPU處理時間,而windows下Sleep()下佔用系統時間。
四、linux時間系統函數
1、gettimeofday
獲取當前時間,返回從計算機元年到現在經歷的時間。
頭文件:
sys/time.h
unistd.h
函數聲明:int gettimeofday(struct timeval* tv, struct timezone* tz);
timeval結構定義爲:
struct timeval
{
long tv_sec; /*秒*/
long tv_usec; /*微秒*/
};
timezone 結構定義爲:
struct timezone
{
int tz_minuteswest; /*和Greenwich 時間差了多少分鐘*/
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年以後)*/
返回值:成功則返回0,失敗返回-1,錯誤代碼存於errno。附加說明EFAULT指針tv和tz所指的內存空間超出存取權限。
2、settimeofday()
設置當前時間,只有root權限才能使用此函數修改時間。
頭文件:
sys/time.h
unistd.h
函數聲明:int settimeofday(struct timeval* tv, struct timezone* tz);
返回值:成功則返回0,失敗返回-1,錯誤代碼存於errno。
錯誤代碼:
EPERM 並非由root權限調用settimeofday(),權限不夠。
EINVAL 時區或某個數據是不正確的,無法正確設置時間。
3、clock_gettime
函數聲明:int clock_gettime(clockid_t clk_id,struct timespec* tp);
clk_id取值
CLOCK_REALTIME:系統從計算機元年到現在的時間,隨系統時間變化而變化
CLOCK_MONOTONIC:系統啓動到現在的時間,不隨系統時間變化而變化
CLOCK_PROCESS_CPUTIME_ID:本進程從啓動到現在CPU花費的時間,sleep和usleep不佔用cpu時間
CLOCK_THREAD_CPUTIME_ID:本線程從啓動到現在CPU花費的時間
timespec結構
struct timespec
{
time_t tv_sec; /* 秒*/
long tv_nsec; /* 納秒*/
};
五、windows時間系統函數
1、GetLocalTime
獲取當前系統時間,以系統時區爲標準,精確到毫秒級。
函數聲明:void GetLocalTime(LPSYSTEMTIME lpSystemTime);
SYSTMETIME結構定義:
typedef struct _SYSTEMTIME
{
WORD wYear;//年
WORD wMonth;//月
WORD wDayOfWeek;//星期
WORD wDay;//日
WORD wHour;//時
WORD wMinute;//分
WORD wSecond;//秒
WORD wMilliseconds;//毫秒
}SYSTEMTIME,*PSYSTEMTIME;
2、GetSystemTime
獲取當前系統時間,以0時區爲標準。
3、SetLocalTime
設置系統本地時間
4、SetSystemTime
設置系統UTC時間
5、GetTickCount
返回操作系統啓動到現在所經過的毫秒數
函數聲明:DWORD GetTickCount(void);
GetTickCount()和Clock()函數是向主板BIOS要real time clock時間,會有中斷產生,以及延遲問題。
6、QueryPerformaceFrequency和QueryPerformanceCounter
返回硬件支持的高精度計數器的頻率,返回系統從啓動到現在的時間。
函數聲明:
BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
BOOL QueryPerformanceCounter (LARGE_INTEGER *lpCount);
參數類型定義如下:
typeef union _ LARGE_INTEGER
{
struct
{
DWORD LowPart;
LONG HighPart;
};
LONGLONG QuadPart;
} LARGE_INTEGER;
QueryPerformanceCounter獲取系統啓動到現在計數器時鐘數。QueryPerformanceFrequency獲取系統的時鐘頻率,也就是每秒系統的時鐘數。
例子:
#include <windows.h>
int main()
{
LARGE_INTEGER lagerCounter1;
QueryPerformanceCounter(&lagerCounter1);
long long llCounter1 = lagerCounter1.QuadPart;
Sleep(2000);
LARGE_INTEGER lagerCounter2;
QueryPerformanceCounter(&lagerCounter2);
long long llCounter2 = lagerCounter2.QuadPart;
LARGE_INTEGER largerFreq;
QueryPerformanceFrequency(&largerFreq);
long long llFreq = largerFreq.QuadPart;
double dIntervals = (llCounter2 - llCounter1) / llFreq;
printf("the interval is: %f",dIntervals);
}
例子輸出爲2.0。
參考:
1.https://blog.csdn.net/hmxz2nn/article/details/77986450
2.https://blog.csdn.net/tsx86/article/details/49965171
3.https://blog.csdn.net/weixin_34295316/article/details/86061183