FILETIME 到底能撐到哪一年才不出包?
Raymond Chen・The Old New Thing・2026-09-21
FILETIME 型別的合法上界是0x7FFFFFFF`FFFFFFFF,一旦超過這個值,CreateWaitableTimer 之類的函式就會把最高位當成負號,把它解讀成「負的相對時長」而不是絕對時間點,甚至有程式會把它當成早於西元 1601 年 1 月 1 日的時間。Raymond Chen 在《Old New Thing》這篇文章裡,拆解了 FILETIME 邊界值背後的來龍去脈。
背景
這篇文章的起點,是一位工程師想定義一個哨兵用的 FILETIME,讓它拿去跟任何其他 FILETIME 比較時,透過 CompareFileTime 永遠顯示自己比較晚。最直覺的作法,是挑 FILETIME 型別能表示的最大位元組合來當這個哨兵值。但 Raymond Chen 指出,這個直覺一路會撞上好幾層陷阱,牽扯到 SetFileTime、CreateWaitableTimer、SYSTEMTIME,甚至 CLR 的 System.DateTime 與特定行事曆型別的年份上限。換句話說,一個看似單純的「挑最大值」決定,同時牽動了作業系統 API、CLR 執行環境,以及行事曆資料表三個不同層級的邊界。
規格細節
FILETIME 本質上是從西元 1601 年 1 月 1 日起算的無號 tick 數,照定義推算,理論最大值應該是 0xFFFFFFFF`FFFFFFFF。但這個數值早被保留做特殊用途:SetFileTime 把它當成「不要更新這個 handle 的時間」的訊號,並非真正的時間戳。工程師常見的誤解,就是把「型別能表示的最大位元組合」誤當成「可以安全使用的最大時間值」,這兩者其實差了關鍵的一個位元。這也是為什麼只看型別定義就假設某個極端數值可以直接拿來用,是相當危險的做法。
真正安全的上限,是最高位保持 0 的 0x7FFFFFFF`FFFFFFFF,再往上至少會踩到兩個問題。CreateWaitableTimer 會把最高位當成正負號解讀;FileTimeToSystemTime 則直接拒絕轉換超過這個值的 FILETIME。
影響範圍
下表整理了 FILETIME 上界,以及與其他 Windows、CLR 時間型別上限的對照關係,換算時可以直接查表。
| 數值 / 型別 | 意義 |
|---|---|
0xFFFFFFFF`FFFFFFFF | 64 位元無號整數最大值,被 SetFileTime 保留為特殊訊號,非合法時間戳 |
0x7FFFFFFF`FFFFFFFF | FILETIME 建議的安全上界,最高位為 0 |
| 西元 30828 年 | FileTimeToSystemTime 能把安全上界轉成的最大 SYSTEMTIME 日期 |
| 西元 30827 年底 | SystemTimeToFileTime 支援轉換的最後日期,比前者少一年 |
| 西元 9999 年 | CLR 的 System.DateTime 上限 |
| 西元 2101 年初 | ChineseLunisolarCalendar 因對照表長度而定的上限 |
FileTimeToSystemTime 願意把 0x7FFFFFFF`FFFFFFFF 轉成西元 30828 年的 SYSTEMTIME,但反過來呼叫 SystemTimeToFileTime 卻會失敗,因為它只支援到西元 30827 年年底為止。就算硬是拿 30827 年最後一毫秒去轉,實際數值還會因為閏秒資料庫累積了多少筆閏秒而有所不同。
這代表任何自行往返轉換 FILETIME 與 SYSTEMTIME 的程式碼,都不能假設「能轉出去就一定轉得回來」。對負責 Windows 時間戳序列化、跨語言時間轉換的工程師來說,這篇文章點出真正該檢查的邊界:不要拿 0xFFFFFFFF`FFFFFFFF 或任何逼近上限的數值當哨兵值,一旦這種值不小心流出你的程式碼,時區調整、「一天後」這類加法運算、或轉成 C# 的 System.DateTime 都可能溢位。
回到文章開頭那個哨兵值的問題,如果只是需要一個保證比任何值都晚、拿去跟 CompareFileTime 比較用的數字,0xFFFFFFFF`FFFFFFFF 的確是 CompareFileTime 支援的最大值,但前提是你絕不能讓這個值逃出你自己的程式碼。Raymond Chen 建議改用型別系統本身的手段,例如 C++ 的 std::optional<FILETIME> 或 C# 的 Nullable<DateTime> 來表示「沒有時間值」,而不是把極端數字塞進 FILETIME 欄位本身。這樣每個消費端都能依照自己語言的慣例去處理空值,不必共享同一組容易被誤用的魔術數字。換句話說,讓特殊數字留在 FILETIME 型別內部本身,才是問題的根源,而不是選錯了哪一個具體數值。
原始來源:The Old New Thing - What's the highest legal FILETIME? Is it safe to use?