C/C++獲取時間及格式化


  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參考如下表列出格式。

---strftime格式化說明---
     格  式      說        明
%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();

--------------待完善--------------


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM