C庫中與系統時間相關的函數定義在<time.h>頭文件中, C++定義在<ctime>頭文件中,Windows系統API調用獲取時間的系統API時需要 #include<Windows.h>。下面為基本概念,有助於理解后面API功能使用的理解。
Coordinated Universal Time(UTC)協調世界時,又稱為世界標准時間,也就是大家所熟知的格林威治標准時間(Greenwich Mean Time,GMT)。比如,中國內地的時間與UTC的時差為+8,也就是UTC+8。美國是UTC-5。
Calendar Time 日歷時間,是用“從一個標准時間點到此時的時間經過的秒數”來表示的時間。這個標准時間點對不同的編譯器來說會有所不同,但對一個編譯系統來說,這個標准時間點是不變的,該編譯系統中的時間對應的日歷時間都通過該標准時間點來衡量,所以可以說日歷時間是“相對時間”,但是無論你在哪一個時區,在同一時刻對同一個標准時間點來說,日歷時間都是一樣的。
clock tick 時鍾計時單元(而不把它叫做時鍾滴答次數),一個時鍾計時單元的時間長短是由CPU控制的。一個clock tick不是CPU的一個時鍾周期,而是C/C++的一個基本計時單位。
一、C/C++ 獲取時間並格式化輸出
詳細請參考C/C++獲取時間函數。
1. 計時函數
1)clock_t clock(void);
返回從“開啟這個程序進程”到“程序中調用clock()函數”時 之間的CPU時鍾計時單元(clock tick)數,MSDN稱掛鍾時間(wall-clock),clock_t的類型定義如下,clock_t是一個long類型的數:
1 #ifndef _CLOCK_T_DEFINED 2 typedef long clock_t; 3 #define _CLOCK_T_DEFINED 4 #endif
1 //常量,表示一秒鍾會有多少個時鍾計時單元 2 #define CLOCKS_PER_SEC ((clock_t)1000)
2)double difftime(time_t time1, time_t time0);
只能精確到秒(並不說明該時間具有double一樣的精度),這是由其傳入參數決定的。
3)DWORD WINAPI GetTickCount(VOID);
在Release版本中,該函數從0開始計時,返回自設備啟動后的毫秒數(不含系統暫停時間)。對於一般的實時控制,使用GetTickCount()函數就可以滿足精度要求,但要進一步提高計時精度,就要采用QueryPerformanceFrequency()函數和QueryPerformanceCounter()函數。這兩個函數是VC提供的僅供Windows 9X使用的高精度時間函數,並要求計算機從硬件上支持高精度計時器。
1 #include<winbase.h> 2 #define GetCurrentTime() GetTickCount()
1 #include<sysinfoapi.h>
2 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
3
4 __drv_preferredFunction("GetTickCount64", "GetTickCount overflows roughly every 49 days. Code that does not take that into account can loop indefinitely. GetTickCount64 operates on 64 bit values and does not have that problem")
5 WINBASEAPI 6 DWORD 7 WINAPI 8 GetTickCount( 9 VOID 10 ); 11 #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
我在具體使用時直接調用獲取的是time_t/DWORD類型值不是電腦當前准確時間,而是1970年的某一個時間,所以千萬不要誤用。同時還應該與CTime類中的GetCurrentTime區分開來。
2. 獲取當前日歷時間 time_t time (time_t* timer)
1 #ifndef _TIME_T_DEFINED 2 typedef long time_t; 3 #define _TIME_T_DEFINED 4 #endif
參數及返回值類型說明:對time_t數據類型的值來說,它所表示的時間不能晚於2038年1月18日19時14分07秒,部分編譯器如VC++采用了__time64_t並通過_time64()函數來獲得日歷時間,這樣就可以通過該數據類型保存3001年1月1日0時0分0秒(不包括該時間點)之前的時間。
參數及返回值說明:C 庫函數 time_t time(time_t *seconds) 返回自紀元 Epoch(1970-01-01 00:00:00 UTC)起經過的時間,以秒為單位。如果 seconds 不為空,則返回值也存儲在變量 seconds 中。
3. 常用結構體tm
1 #ifndef _TM_DEFINED 2 struct tm 3 { int tm_sec; /* 秒 – 取值區間為[0,59] */ 4 int tm_min; /* 分 - 取值區間為[0,59] */ 5 int tm_hour; /* 時 - 取值區間為[0,23] */ 6 int tm_mday; /* 一個月中的日期 - 取值區間為[1,31] */ 7 int tm_mon; /* 月份(從一月開始,0代表一月) - 取值區間為[0,11] */ 8 int tm_year; /* 年份,其值等於實際年份減去1900 */ 9 int tm_wday; /* 星期 – 取值區間為[0,6],其中0代表星期天,1代表星期一,以此類推 */ 10 int tm_yday; /* 從每年的1月1日開始的天數 – 取值區間為[0,365],其中0代表1月1日,1代表1月2日,以此類推 */ 11 int tm_isdst; /* 夏令時標識符,實行夏令時,tm_isdst為正。不實行夏令時,tm_isdst為0;不了解情況時,tm_isdst()為負。*/ 12 }; 13 #define _TM_DEFINED 14 #endif
需要注意的是進行年份計算時+1900,月份計算+1,或者:
真實_year = tm_year + 1900;
真實_month = tm_mon + 1;
4. 獲得時間及格式化、轉換函數
1) 獲得日期和時間
1 struct tm * gmtime(const time_t *timer); //將日歷時間轉化為世界標准時間(即格林尼治時間),並返回一個tm結構體來保存這個時間 2 struct tm * localtime(const time_t * timer); //將日歷時間轉換為本地時間,從1970年起始的時間戳轉換為1900年起始的時間數據結構
比如現在用gmtime()函數獲得的世界標准時間是2005年7月30日7點18分20秒,那么我用localtime()函數在中國地區獲得的本地時間會比時間標准時間晚8個小時,即2005年7月30日15點18分20秒。
1 #include "time.h" 2 #include "stdio.h" 3 int main(void) 4 { 5 struct tm *local; 6 time_t t; 7 t=time(NULL); 8 local=localtime(&t); 9 printf("Local hour is: %d/n",local->tm_hour); 10 local=gmtime(&t); 11 printf("UTC hour is: %d/n",local->tm_hour); 12 return 0; 13 }
2) 時間格式及轉換
1 char * asctime(const struct tm * timeptr); //通過tm結構來生成具有固定格式的保存時間信息的字符串(只是把tm結構對象中的各個域填到時間字符串的相應位置就行了) 2 char * ctime(const time_t *timer); //通過日歷時間來生成時間字符串(需要先參照本地的時間設置,把日歷時間轉化為本地時間,然后再生成格式化后的字符串)
以上返回值char*格式均為星期幾 月份 日期 時:分:秒年/n/0 ,例如:Wed Jan 02 02:03:55 1980/n/0.
1 time_t mktime(struct tm * timeptr); //將用tm結構表示的時間轉化為日歷時間
每種系統平台提供的參照時間可能不同,但這不是我們變成所關注的焦點,因為其處理細節已經被封裝,只需大膽調用即可。
3) 自定義時間格式
1 size_t strftime( char *strDest, size_t maxsize, const char *format, const struct tm *timeptr ); //類似於sprintf()
參考Linux時間編程之strftime():格式化輸出好幫手,其中const char* format參考如下表列出格式。
格 式 | 說 明 |
%a | 星期幾的簡寫 |
%A | 星期幾的全稱 |
%b | 月分的簡寫 |
%B | 月份的全稱 |
%c | 標准的日期的時間串 |
%C | 年份的后兩位數字 |
%d | 十進制表示的每月的第幾天 |
%D | 月/天/年 |
%e | 在兩字符域中,十進制表示的每月的第幾天 |
%F | 年-月-日 |
%g | 年份的后兩位數字,使用基於周的年 |
%G | 年分,使用基於周的年 |
%h | 簡寫的月份名 |
%H | 24小時制的小時 |
%I | 12小時制的小時 |
%j | 十進制表示的每年的第幾天 |
%m | 十進制表示的月份 |
%M | 十時制表示的分鍾數 |
%n | 新行符 |
%p | 本地的AM或PM的等價顯示 |
%r | 12小時的時間 |
%R | 顯示小時和分鍾:hh:mm |
%S | 十進制的秒數 |
%t | 水平制表符 |
%T | 顯示時分秒:hh:mm:ss |
%u | 每周的第幾天,星期一為第一天 (值從0到6,星期一為0) |
%U | 第年的第幾周,把星期日做為第一天(值從0到53) |
%V | 每年的第幾周,使用基於周的年 |
%w | 十進制表示的星期幾(值從0到6,星期天為0) |
%W | 每年的第幾周,把星期一做為第一天(值從0到53) |
%x | 標准的日期串 |
%X | 標准的時間串 |
%y | 不帶世紀的十進制年份(值從0到99) |
%Y | 帶世紀部分的十制年份 |
%z,%Z | 時區名稱,如果不能得到時區名稱則返回空字符 |
%% | 百分號 |
二、Windows系統獲取時間
Windows關於時間的結構體如下所示。
1 typedef struct _SYSTEMTIME 2 { 3 WORD wYear ; // 年 4 WORD wMonth ; // 月 5 WORD wDayOfWeek ; // 星期,0=星期日,1=星期一... 6 WORD wDay ; // 日 7 WORD wHour ; // 時 8 WORD wMinute ; // 分 9 WORD wSecond ; // 秒 10 WORD wMilliseconds ; // 毫秒 11 } SYSTEMTIME;
1. 系統API GetSystemTime()
函數原型如下,lpSystemTime可以直接 填寫 SYSTEMTIME 類型,但是 必須 要加上 &,即為指針類型值。
1 //#include<sysinfoapi.h>中聲明的 2 WINBASEAPI VOID WINAPI GetSystemTime (LPSYSTEMTIME lpSystemTime);
GetSystemTime所返回的是UTC協調世界時(Coordinated Universal Time,簡寫作UTC,之前也被拼做Universal Time Coordinated,有時是Universal Coordinated Time)。它是由國際無線電咨詢委員會定義和建議采用的,並由國際時間局(BIH)負責保持的以國際單位制(SI)秒為單位的時間標度。對與無線電規則相關的大部分實際應用而言,協調世界時(UTC)與本初子午線(經度零度)上的平均太陽時等效。該時間過去以格林威治平均時(GMT)表示。
協調世界時使用24小時制的時鍾表示,但也可以被轉換為12小時制的時鍾(AM和PM)。UTC用於飛行和航海,它有時也被稱作祖魯。UTC使用陽歷。
2. 系統API GetLocalTime()
GetLocalTime獲得的時間是基於本地時間的。
1 //#include<sysinfoapi.h>中聲明的 2 WINBASEAPI VOID WINAPI GetLocalTime(LPSYSTEMTIME lpSystemTime);
如GetLocalTime獲得的本地主機的時間是上午8時,當用GetSystemTime獲取時,該時間是0時,注意這兩個函數的區別!
3. time_t、SYSTEMTIME和tm格式相互轉換
1)time_t 轉 SYSTEMTIME。
1 const SYSTEMTIME Time_tToSystemTime(time_t t) 2 { 3 tm temptm; 4 localtime_s(&temptm, &t); 5 SYSTEMTIME st = { 1900 + temptm.tm_year, 6 1 + temptm.tm_mon, 7 temptm.tm_wday, 8 temptm.tm_mday, 9 temptm.tm_hour, 10 temptm.tm_min, 11 temptm.tm_sec, 12 0 }; 13 return st; 14 }
2)SYSTEMTIME 轉 time_t。
1 const time_t SystemTimeToTime_t(const SYSTEMTIME& st) 2 { 3 struct tm gm = { st.wSecond, st.wMinute, st.wHour, st.wDay, st.wMonth - 1, st.wYear - 1900, st.wDayOfWeek, 0, 0 }; 4 return mktime(&gm); 5 }
三、MFC獲取系統時間
CTime的靜態成員函數GetCurrentTime(),獲取系統當前時間。
#include <ctime>
1 // CTime類中的靜態成員函數 2 CTime t = CTime::GetCurrentTime(); 3 int d = t.GetDay(); // 獲得幾號 4 int y = t.GetYear(); 5 int m = t.GetMonth(); 6 int h = t.GetHour(); 7 int mm = t.GetMinute(); 8 int s = t.GetSecond(); 9 int w = t.GetDayOfWeek(); // 獲取星期幾,1為星期天,7為星期六 10 CString strTime = t.Format(_T("%Y-%m-%d %H:%M:%S")); 11 12 // 如果想計算兩端時間的差值,可以使用CTimeSpan類 13 CTime t1(1999, 3, 19, 22, 15, 0); 14 CTimeSpan span = t - t1; 15 int iDay = span.GetDays(); // 獲取這段間隔共有多少天 16 int iHour = span.GetTotalHours(); // 共有多少小時 17 int iMin = span.GetTotalMinutes(); // 共有多少分鍾 18 int iSec = span.GetTotalSeconds(); // 共有多少秒 19 20 SYSTEMTIME sysTm, LocTm; 21 GetSystemTime(&sysTm); // 獲取格林威治標准時間,與北京時間相差8小時 22 GetLocalTime(&LocTm); // 獲取本時區時間,中國即東八區北京時間 23 // 獲取當前時間與1970年1月1日0點0時0分的秒數差 24 CTime t2 = CTime::GetCurrentTime();
--------------待完善--------------