IO.File.GetLastAccessTime 關閉一小時
我正在開發一個程序,該程序記錄文件中的日期元數據,例如創建時間、上次修改時間等。該程序的舊版本是用 VBA 編寫的,並且執行以下操作:
Public Function GetFileLastAccessTime(ByVal FilePath As String) As Date Dim fso As New Scripting.FileSystemObject Dim f As Scripting.File Set f = fso.GetFile(FilePath) GetFileLastAccessTime = f.DateLastAccessed End Function相關文件的輸出:
?getfilelastaccesstime("SomePath") 7/30/2010 2:16:07 PM這是我從 Windows Exploder 中的文件屬性中獲得的值。幸福。
我將此功能移植到 VB.Net 應用程序。新程式碼:
Public Function GetLastAccessTime(ByVal FilePath As String) As Date Return IO.File.GetLastAccessTime(FilePath) End Function簡單本身。輸出:
?GetLastAccessTime("SomePath") #7/30/2010 3:16:07 PM#一小時後。
這兩個函式都在同一台機器上執行,檢查同一個文件。我也嘗試過使用具有相同結果的 IO.FileInfo 類。我檢查了數千個文件,它們都關閉了一小時。創建時間和上次修改時間的其他日期屬性也關閉一小時。
幫助!
我忘了在原帖中提到,電腦的時區是 CST,目前沒有夏令時。
我已經在 Windows 7 64 位和 Windows XP 32 位上重現了這個問題。
謝謝。
2011 年 1 月 6 日更新:
感謝所有建議嘗試使用適當的時區偏移量從 UTC 計算所需日期的人。在這個時候,我決定這樣做不值得冒險。對於這個特定的業務需求,最好說日期值不是您所期望的,因為這正是 API 的工作方式。如果我試圖“修復”它,那麼我擁有它,我寧願不這樣做。
只是為了好玩,我嘗試通過互操作使用舊的 Scripting.FileSystemObject。它給出了與 Windows Explorer 一致的預期結果,與 System.IO 相比,性能損失約為 5 倍。如果事實證明我必須得到與 Windows 資源管理器相匹配的日期,我會硬著頭皮走這條路。
我嘗試的另一個實驗是通過 C# 直接進入 kernel32 中的 GetFileTime API 函式:
[DllImport("kernel32.dll", SetLastError = true)] private static extern bool GetFileTime( IntPtr hFile, ref FILETIME lpCreationTime, ref FILETIME lpLastAccessTime, ref FILETIME lpLastWriteTime );這導致了 System.IO 的完全相同的行為,時間從 Windows 資源管理器中減少了一個小時。
再次感謝大家。
我可以在 XP/Win2k3/Vista 上使用 .NET 4.0 和 2.0/3.5 重現這一點。
問題是 DST 與現在處於不同的狀態,並且 .NET 處理這種差異的方式與 Explorer 和
Scripting.FileSystemObject.(當 DST 與壓縮文件時不同時,從 zip 文件中提取文件時,您會看到類似的問題。)
通過 Reflector,.NET 與非 .NET 程式碼路徑不同的原因是
IO.File( 和IO.FileInfo) 中的所有三個本地日期戳都被實現為獲取 Utc 日期戳和應用.ToLocalTime,它根據 DST 是否在本地發生來確定要添加的偏移量UTC 時間的時區。我還檢查了,通過將日期更改為去年的 7 月 1 日,創建一個文件並查看當我返回目前日期(3 月 16 日)時的時間戳(我在南澳大利亞,所以我們現在在 DST 並沒有7 月 1 日),並且 Windows(並且可能)現在
FileSystemObject將 DST 添加到位,因此顯示的時間實際上會發生變化。所以,總而言之,.NET 更正確。
但是,如果您想要不正確但與 Explorer 相同的日期,請使用:
Public Function GetLastAccessTime(ByVal FilePath As String) As Date Return IO.File.GetLastAccessTimeUtc(FilePath) _ .Add(TimeZone.CurrentTimeZone.GetUtcOffset(Now)) End Function這已經在Raymond Chen 的部落格上討論過(總結是:.NET 直覺正確但並不總是可逆,Win32 嚴格正確且可逆)。