Dot-Net

IO.File.GetLastAccessTime 關閉一小時

  • November 16, 2017

我正在開發一個程序,該程序記錄文件中的日期元數據,例如創建時間、上次修改時間等。該程序的舊版本是用 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 嚴格正確且可逆)。

引用自:https://stackoverflow.com/questions/4605983