電腦的幾種時間格式
一.FILETIME和SYSTEMTIME格式
我遇到的第一種時間格式是在使用函數GetFileTime時返回的 FILETIME,這是一個64位(8位元組)結構。在SDK文檔中,關於這個結構是這樣描述的“FILETIME結構的64位值,表示從1601年1月1 日開始的以100納秒(一納秒為十億分之一秒)為間隔的值”。我不知道你——反正我的朋友和親戚——在聽到“100納秒”時頭都大了。
不過還好,Win32的另一種時間格式消除了這個問題,這個格式就是 SYSTEMTIME。它是一個包含有年、月、日、小時、分、秒、微秒這些成員的結構,而且還有一個API函數FileTimeToSystemTime 專門用來將FILETIEM格式轉化成SYSTEMTIME格式。當然,假如你要知道是否為閏年、閏紀等這樣的問題就只好自己手工轉換了。
每次運行使用GetFileTime和FileTimeToSystemTime函數 的代碼,我總是發現得出的時間比正確的時間少幾個小時。為什麼呢?思來想去,我終於明白了:在安裝WINDOWS NT和95時,我曾經告訴系統我住在什麼地區。而在win32下,FILETIME總是為格林尼治時間(UTC)。使用UTC,你就會發現實際時間是美國 新罕布希爾州的南雪(Nashua)只有2PM,而得到的時間卻是格林尼治7PM。
如果讓程式員對每個FILETIME都負責檢查並修正,這太可怕了。這就是WIN32 提供FileTimeToLocalTime函數的原因。在調用FileTimeToSystemTime前先調用 FileTimeToLocalFileTime,可以非常方便地對FILETIME進行時區修正。
二.MS-DOS格式
第三種描繪時間的格式是一種老式的MS-DOS格式。在這種格式下,日期和時間被獨立 儲存在兩個雙字中。因為只有16位,所以年度值是相對於1980年的差值。而且,這種格式時間精度是2秒。如果你選擇使用這種格式,那麼函數 FileTimeToDosDateTime是不能缺少的。
我怎麼會想到這種時間格式呢?真不好意思,當我在開發DEPENDS程式時,開始我並沒有想到要使用SYSTEMTIME格式。所以,一直到我意識到這個問題之前,所有版本的DEPENDS都是將FILETIME轉換成MS-DOS格式的。
三.PE檔案中的時間戳記
第四種時間格式在我們平常的API文檔中是不會見到的。在WIN32可執行檔中, PE檔案頭部(IMAGE_FILE_HEADER)中有個DWORD欄位TimeDateStamp。它是從格林尼治時間1970年1月1日夜裡12: 00開始的秒數。TimeDateStamp由連接器(linker)設定,並且在PE檔案的其它部分也有使用。
在這裡,我要承認我以前犯的一個愚蠢的錯誤。在我的文章《Peering Inside the PE: A Tour of the Win32 Portable Executable File Format》 (MSJ March 1994)和書《Windows 95 System Programming Secrets》中,我將TimeDateStamp欄位描述成從1969年12月31日4PM開始的秒數。我得到這個結果是因為我將 TimeDateStamp設定為0,然後運行DUMPBIN來看轉換成什麼時間。在這裡我沒有考慮到DUMPBIN已經幫我把時間轉換成電腦當前時區 的時間(我的時區當然不會是格林尼治時區)了。所以,在這裡我再次糾正這個錯誤。
TimeDateStamp這個欄位在PE檔案中相當有用。比如,當你在檔案系統中改 變了檔案的日期和時間後,TimeDateStamp卻會保持不變。這樣,當你想知道檔案到底什麼時候建立時,TimeDateStamp是比較準確(當 然前提是連接器正確設定了它)。TimeDateStamp的唯一需要點技術的地方是:怎樣將它轉變成我們比較熟悉的時間格式。
經過考慮,我是這樣來解決這個問題的。FILETIME和TimeDateStamp 分別相對於某個時間點的值。如果我能用FILETIME來描述TimeDateStamp,我就可以使用上面提到的Win32時間函數來做我想做的任何事 情。所以我需要先將1970年1月1日表示成FILETIME格式,然後再將TimeDateStamp(以秒數為計數單位)轉換成以100納秒為計數單 位,最後將上面得到的兩個值相加就可以得到我想要的FILETIME格式了。
為了將1970年1月1日轉換成FILETIME,我首先定義了一個 SYSTEIMTIME結構,然後將1970年1月1日填空進去,接著我只要調用SystemTimeToFileTime便可以得到FILETIME格 式了。轉換的結果我在DEPENDS代碼用到:0x019DB1DED53E8000。將秒數轉換成100納秒比較簡單:只要乘上10000000。當 然,結果肯定會超過32位,所以一定要將其中的被乘數強製成64位整數(VC中的_INT64)。當然,如果你想省點事,你完全可以使用C運行庫中的 ctime函數。
四.MAC作業系統中的longdt時間
和FILETIME一樣,這種時間也是個8位元組資料格式,而且也是相對於一個時間點的秒數的計數。但不幸的是:這個時間點和FILETIME不同,它是1904年1月1日午夜12:00。
--------------------------------------------------
電腦的幾種時間格式
注意:本文大部分翻譯自Matt Pietrek 在1997年2月MSJ上的Under The Hood專欄。連結:http://www.microsoft.com/msj/0297/hood/hood0297.aspx 一.FILETIME和SYSTEMTIME格式 我遇到的第一種時間格式是在使用函數GetFileTime時返回的FILETIME, 這是一個64位(8位元組)結構。在SDK文檔中,關於這個結構是這樣描述的“FILETIME結構的64位值,表示從1601年1月1日開始的以100納 秒(一納秒為十億分之一秒)為間隔的值”。我不知道你——反正我的朋友和親戚——在聽到“100納秒”時頭都大了。 不過還好,Win32的另一種時間格式消除了這個問題,這個格式就是 SYSTEMTIME。它是一個包含有年、月、日、小時、分、秒、微秒這些成員的結構,而且還有一個API函數FileTimeToSystemTime 專門用來將FILETIEM格式轉化成SYSTEMTIME格式。當然,假如你要知道是否為閏年、閏紀等這樣的問題就只好自己手工轉換了。 每次運行使用GetFileTime和FileTimeToSystemTime函數的 代碼,我總是發現得出的時間比正確的時間少幾個小時。為什麼呢?思來想去,我終於明白了:在安裝WINDOWS NT和95時,我曾經告訴系統我住在什麼地區。而在win32下,FILETIME總是為格林尼治時間(UTC)。使用UTC,你就會發現實際時間是美國新罕布希爾州的南雪(Nashua)只有2PM,而得到的時間卻是格林尼治7PM。 如果讓程式員對每個FILETIME都負責檢查並修正,這太可怕了。這就是WIN32提 供FileTimeToLocalTime函數的原因。在調用FileTimeToSystemTime前先調用 FileTimeToLocalFileTime,可以非常方便地對FILETIME進行時區修正。 二.MS-DOS格式
第三種描繪時間的格式是一種老式的MS-DOS格式。在這種格式下,日期和時間被獨立存
儲在兩個雙字中。因為只有16位,所以年度值是相對於1980年的差值。而且,這種格式時間精度是2秒。如果你選擇使用這種格式,那麼函數
FileTimeToDosDateTime是不能缺少的。 我怎麼會想到這種時間格式呢?真不好意思,當我在開發DEPENDS程式時,開始我並沒有想到要使用SYSTEMTIME格式。所以,一直到我意識到這個問題之前,所有版本的DEPENDS都是將FILETIME轉換成MS-DOS格式的。 三.PE檔案中的時間戳記 第四種時間格式在我們平常的API文檔中是不會見到的。在WIN32可執行檔中,PE
檔案頭部(IMAGE_FILE_HEADER)中有個DWORD欄位TimeDateStamp。它是從格林尼治時間1970年1月1日夜裡12:00
開始的秒數。TimeDateStamp由連接器(linker)設定,並且在PE檔案的其它部分也有使用。 在這裡,我要承認我以前犯的一個愚蠢的錯誤。在我的文章《Peering Inside
the PE: A Tour of the Win32 Portable Executable File Format》 (MSJ March
1994)和書《Windows 95 System Programming
Secrets》中,我將TimeDateStamp欄位描述成從1969年12月31日4PM開始的秒數。我得到這個結果是因為我將
TimeDateStamp設定為0,然後運行DUMPBIN來看轉換成什麼時間。在這裡我沒有考慮到DUMPBIN已經幫我把時間轉換成電腦當前時區
的時間(我的時區當然不會是格林尼治時區)了。所以,在這裡我再次糾正這個錯誤。 TimeDateStamp這個欄位在PE檔案中相當有用。比如,當你在檔案系統中改變
了檔案的日期和時間後,TimeDateStamp卻會保持不變。這樣,當你想知道檔案到底什麼時候建立時,TimeDateStamp是比較準確(當然
前提是連接器正確設定了它)。TimeDateStamp的唯一需要點技術的地方是:怎樣將它轉變成我們比較熟悉的時間格式。 經過考慮,我是這樣來解決這個問題的。FILETIME和TimeDateStamp分
別相對於某個時間點的值。如果我能用FILETIME來描述TimeDateStamp,我就可以使用上面提到的Win32時間函數來做我想做的任何事
情。所以我需要先將1970年1月1日表示成FILETIME格式,然後再將TimeDateStamp(以秒數為計數單位)轉換成以100納秒為計數單
位,最後將上面得到的兩個值相加就可以得到我想要的FILETIME格式了。 為了將1970年1月1日轉換成FILETIME,我首先定義了一個
SYSTEIMTIME結構,然後將1970年1月1日填空進去,接著我只要調用SystemTimeToFileTime便可以得到FILETIME格
式了。轉換的結果我在DEPENDS代碼用到:0x019DB1DED53E8000。將秒數轉換成100納秒比較簡單:只要乘上10000000。當
然,結果肯定會超過32位,所以一定要將其中的被乘數強製成64位整數(VC中的_INT64)。當然,如果你想省點事,你完全可以使用C運行庫中的
ctime函數。 四.MAC作業系統中的longdt時間 和FILETIME一樣,這種時間也是個8位元組資料格式,而且也是相對於一個時間點的秒數的計數。但不幸的是:這個時間點和FILETIME不同,它是1904年1月1日午夜12:00。 受上面文章的啟發,我寫了個將longdt轉換到FILETIME格式的函數:
function LongDtToFileTime(ldt: INT64): FILETIME;var ft1904: FILETIME; st1904: SYSTEMTIME;begin st1904.wYear := 1904; st1904.wMonth := 1; st1904.wDay := 1; st1904.wHour := 0; st1904.wMinute := 0; st1904.wSecond := 0; st1904.wMilliseconds := 0; SystemtimeToFileTime(st1904, ft1904); ldt := ldt * 10000000; ldt := ldt + (int64(ft1904)); FileTimeToLocalFileTime(FILETIME(ldt), FILETIME(ldt)); Result := FILETIME(ldt);end; |