Windows中的時間(SYSTEMTIME和FILETIME)&CRT中的時間(time_t和tm)

來源:互聯網
上載者:User

http://blog.csdn.net/bokee/article/details/5330791

http://blog.csdn.net/bokee/article/details/5330682

 

時間處理時實際項目中經常碰到的問題,這裡介紹最常用的時間處理函數。

首先介紹基本的時間概念。時間一般分為兩種,一種是本地時間(Local Time),一種是國際標準時間間(Coordinated Universal Time ,UTC),也就是傳說中的格林威治時間。本地時間與UTC時間之間的差即為時差,比如,北京時間(東八區)比UTC時間晚8個小時。

C運行庫中處理時間的函數主要是這四個:

[cpp]
view plaincopyprint?
  1. time_t time(
  2. time_t *timer);

time_t類型為32位或64位整型,具體類型由編譯系統決定。此函數用來獲得從1970年1月1日子夜(這個時刻在不同的CRT實現中可能會不一樣)到當前時刻以來所流逝的時間,以秒為單位。這個時間差叫做日曆時間(Calendar Time )。

這是當然讓我困惑的地方:這個特殊的時刻——1970年1月1日零時零分零秒——是指本地時間呢,還是UTC時間呢?我認為是本地時間,也就是各個時區自己的1970年1月1日零時零分零秒。可以設想這樣一種情況,如果全球24時區各有一台電腦,都依次在自己所在時區的本地時間1970年1月1日零時1分零秒調用time函數,那麼傳回值都是60。注意,這裡是依次調用(事實上是每隔1小時),而不是想象中的同時調用,這是因為相鄰時區的同一本地時間,總是相差1小時。

當然,time_t型的時間方便電腦處理,但普通使用者無法理解這種數字。所以我們通常需要將time_t型時間轉換成我們平常所見的年月日形式。CRT中為此定義了tm結構。

[cpp]
view plaincopyprint?
  1. struct tm {
  2. int tm_sec; /* seconds after the minute - [0,59] */
  3. int tm_min;
    /* minutes after the hour - [0,59] */
  4. int tm_hour; /* hours since midnight - [0,23] */
  5. int tm_mday;
    /* day of the month - [1,31] */
  6. int tm_mon; /* months since January - [0,11] */
  7. int tm_year;
    /* years since 1900 */
  8. int tm_wday; /* days since Sunday - [0,6] */
  9. int tm_yday;
    /* days since January 1 - [0,365] */
  10. int tm_isdst; /* daylight savings time flag */
  11. };

注釋中已詳細解釋了各個欄位的用法。顯然這個結構中的欄位對使用者更有意義。我們通常用localtime_s函數將time_t時間轉換為tm時間。

[cpp]
view plaincopyprint?
  1. errno_t localtime_s(
  2. struct tm* _tm,
  3. const time_t *time);

其中第二個參數為傳入的time_t時間,第一個參數為返回的tm時間。由函數名可看出,返回的tm時間表示的是本地時間。當然,我們有時候也需要獲得對應的UTC時間,這時我們需要gmtime函數。

[cpp]
view plaincopyprint?
  1. errno_t gmtime_s(
  2. struct tm* _tm,
  3. const time_t* time);

後面我們會看到兩者的區別。

我們知道了如何將time_t時間轉換為tm時間。同樣,我們會需要將tm表示的時間轉換為time_t時間。這時我們需要mktime函數。

[cpp]
view plaincopyprint?
  1. time_t mktime(
  2. struct tm *timeptr);

此函數返回從"特殊時刻"到參數表示的時刻之間流逝的日曆時間。另外還有個很好用的特性,就是它能修正傳進來的tm結構中各欄位的取值範圍。比如,如果你將tm.tm_mon設為1,tm.tm_day設為33,然後以其為參數調用mktime函數,此函數會將tm.tm_mon修正為2,tm.tm_day修正為2。具體用法參照MSDN。

我們來分析下面範例程式碼:

[cpp]
view plaincopyprint?
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <time.h>
  4. int main()
  5. {
  6. struct tm tmLocal, tmUTC;
  7. time_t tNow;
  8. //Get current calendar time
  9. time(&tNow);
  10. printf("Time Now from time(): %llu/n", tNow);
  11. //Get current local time
  12. localtime_s(&tmLocal, &tNow);
  13. printf("Local Time(YYYY-MM-DD HH:MM:SS): %d-%d-%d %d:%d:%d/n", tmLocal.tm_year + 1900, tmLocal.tm_mon,
  14. tmLocal.tm_mday, tmLocal.tm_hour, tmLocal.tm_min, tmLocal.tm_sec);
  15. //Get UTC time corresponding to current local time, and tmLocal.tm_hour - tmUTC.tm_hour = 8
  16. gmtime_s(&tmUTC, &tNow);
  17. printf("UTC Time (YYYY-MM-DD HH:MM:SS): %d-%d-%d %d:%d:%d/n", tmUTC.tm_year + 1900, tmUTC.tm_mon,
  18. tmUTC.tm_mday, tmUTC.tm_hour, tmUTC.tm_min, tmUTC.tm_sec);
  19. //convert tmLocal to calendar time
  20. tNow = mktime(&tmLocal);
  21. printf("Time Now from mktime(): %llu/n", tNow);
  22. return EXIT_SUCCESS;
  23. }

輸出結果如下:

上面代碼中,11行time函數獲得從"特殊時刻"到當前時刻的日曆時間,如輸出結果中的第一行顯示的1267192581秒。

14行localtime_s函數將日曆時間轉換為本地tm時間,如輸出結果第二行。

18行gmtime_s函數將將日曆時間轉換為對應的UTC的tm時間,如輸出結果第三行顯示。很容易看出,第二,三行輸出的時間相差8小時,因為我在東八區。如果你修改自己電腦的時區(在控制台的Date and Time中修改),再運行此程式,比較兩次的運行結果,你就可以更好的理解了。

22行mktime函數將tm時間轉換為日曆時間,輸出結果中第四行顯示的結果與第一行一樣,這是必須的。。。

//-----------------------------------------------------------------------------------------------------------------------------------------

上文中介紹了C運行庫中的時間處理函數。這一篇介紹Windows SDk中提供的時間函數。兩種時間系統之間沒有本質區別(事實上CRT時間是用Windows時間實現的,當然這是說的VC實現),同樣提供本地時間和UTC時間之間的轉換。不過CRT中的tm時間在SDK中對應為系統時間(SYSTEMTIME),CRT中的time_t時間在SDK中對應的為檔案時間(FILETIME),那個"特殊時刻"也變成1601年1月1日的子夜。

當然,首先要弄清楚FILETIME與SYSTEMTIME定義。

[cpp]
view plaincopyprint?
  1. typedef struct _FILETIME {
  2. DWORD dwLowDateTime;
  3. DWORD dwHighDateTime;
  4. } FILETIME, *PFILETIME;
  5. typedef struct _SYSTEMTIME {
  6. WORD wYear;
  7. WORD wMonth;
  8. WORD wDayOfWeek;
  9. WORD wDay;
  10. WORD wHour;
  11. WORD wMinute;
  12. WORD wSecond;
  13. WORD wMilliseconds;
  14. } SYSTEMTIME, *PSYSTEMTIME;

比較一下,很明顯,FILETIME與time_t類似,是64位整型,不過FILETIME是以100納秒(ns)為單位。SYSTEMTIME與tm類似,不過多了一項wMilliseconds。可以看出,SDK時間比CRT的時間提供了更高的精度。同時SDK提供了更豐富的函數來處理時間。

[c-sharp]
view plaincopyprint?
  1. void GetSystemTime(
  2. LPSYSTEMTIME lpSystemTime);
  3. void GetLocalTime(
  4. LPSYSTEMTIME lpSystemTime);

這兩個函數獲得SYSTEMTIME形式的目前時間,不過GetSystemTime函數獲得當前的UTC時間,GetLocalTime獲得當前的本地時間,可以想象,獲得的兩個時間存在著時差。類似於CRT中提供tm與time_t之間的轉換,SDK也提供了兩個函數來轉換SYSTEMTIME時間與FILETIME時間。

[cpp]
view plaincopyprint?
  1. BOOL SystemTimeToFileTime(
  2. const SYSTEMTIME* lpSystemTime,
  3. LPFILETIME lpFileTime);
  4. BOOL FileTimeToSystemTime(
  5. const FILETIME* lpFileTime,
  6. LPSYSTEMTIME lpSystemTime);

函數命名很self-explanatory,就不用多說了吧。

SDK還提供了兩個很有趣的函數。

[cpp]
view plaincopyprint?
  1. BOOL LocalFileTimeToFileTime(
  2. const FILETIME* lpLocalFileTime,
  3. LPFILETIME lpFileTime);
  4. BOOL FileTimeToLocalFileTime(
  5. const FILETIME* lpFileTime,
  6. LPFILETIME lpLocalFileTime);

LocalFileTimeToFileTime函數將本地的FILETIME時間轉換為對應的UTC的FILETIME時間。我覺得,這個函數只是通過將本地時間減去與UTC時間的時間差來實現轉換,比如在東八區的本地時間轉換為對應的UTC時間,只需要將本地時間減去8*60*60*1000*1000*10(單位100ns)。類似,FileTimeToLocalFileTime函數是將UTC時間轉換為本地時間,它只是將減去時間差換成加上時間差。

瞭解了這些功能,讓我們用代碼說話吧。

[cpp]
view plaincopyprint?
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <time.h>
  4. #include <windows.h>
  5. int main()
  6. {
  7. SYSTEMTIME stLocal, stUTC, stUTC2;
  8. FILETIME ftLocal, ftUTC, ft;
  9. ULARGE_INTEGER uli;
  10. GetLocalTime(&stLocal);
  11. GetSystemTime(&stUTC);
  12. printf("Local System Time(YYYY-MM-DD HH:MM:SS): %d-%d-%d %d:%d:%d/n", stLocal.wYear, stLocal.wMonth,
  13. stLocal.wDay, stLocal.wHour, stLocal.wMinute, stLocal.wSecond);
  14. printf("UTC System Time (YYYY-MM-DD HH:MM:SS): %d-%d-%d %d:%d:%d/n", stUTC.wYear, stUTC.wMonth,
  15. stUTC.wDay, stUTC.wHour, stUTC.wMinute, stUTC.wSecond);
  16. SystemTimeToFileTime(&stLocal, &ftLocal);
  17. uli.LowPart = ftLocal.dwLowDateTime;
  18. uli.HighPart = ftLocal.dwHighDateTime;
  19. printf("Local File Time: %llu/n", uli.QuadPart);
  20. LocalFileTimeToFileTime(&ftLocal, &ftUTC);
  21. uli.LowPart = ftUTC.dwLowDateTime;
  22. uli.HighPart = ftUTC.dwHighDateTime;
  23. printf("UTC File Time: %llu/n", uli.QuadPart);
  24. FileTimeToSystemTime(&ftUTC, &stUTC2);
  25. printf("UTC System Time2 (YYYY-MM-DD HH:MM:SS): %d-%d-%d %d:%d:%d/n", stUTC2.wYear, stUTC2.wMonth,
  26. stUTC2.wDay, stUTC2.wHour, stUTC2.wMinute, stUTC2.wSecond);
  27. return EXIT_SUCCESS;
  28. }

程式輸出結果如下:

代碼13行GetLocalTime函數獲得當前的本地SYSTEMTIME時間,14行獲得對應的UTC的SYSTEMTIME時間,如輸出結果前兩行所顯示,兩者相差8小時(淩晨還在寫部落格,表揚下自己。。。)。

20行SystemTimeToFileTime函數將本地SYSTEMTIME時間轉換為方便計算的本地FILETIME形式時間,如輸出結果第三行所顯示。

25行LocalFileTimeToFileTime函數將本地FileTime時間轉換為對應的UTC的FILETIME時間,如輸出結果第四行所顯示。就像前面介紹的,如果你將輸出結果第三,四兩行所顯示的數字相減,併除以10*1000*1000*60*60,你將會得出8,你可以算下試試,記住FILETIME是以100納秒為單位的。

最後30行FileTimeToSystemTime將FILETIME時間轉換為SYSTEMTIME時間。可以看出輸出結果中第五行與第二行相同,這是必須的,因為兩者都是當前本地時間對應的UTC時間。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.