【发布时间】:2011-01-05 15:45:46
【问题描述】:
我正在开发一个程序,该程序记录文件中的日期元数据,例如创建时间、上次修改时间等。该程序的旧版本是用 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 资源管理器相差一个小时。
再次感谢大家。
【问题讨论】:
-
对我来说似乎是夏令时问题
-
上次访问时间的粒度约为 1 小时。另外请注意,在 Windows Vista 及更高版本中,默认情况下,Last Access Time value is not updated on NTFS Volumes by default.
-
夏令时现在没有生效,但是文件最后一次修改时是生效的。谁是对的?在 UTC 工作以避免不得不问这个问题。
-
不幸的是,不能在 UTC 工作,我需要报告其原始时区的日期。
-
我也想了解为什么 Windows Explorer 和 Scripting.FileSystemObject 在时间上一致,而 IO.File 却不一致。