IO.File.GetLastAccessTime关闭了一个小时

时间:2011-01-05 15:45:46

标签: .net vb.net datetime vba

我正在开发一个记录文件中日期元数据的程序,例如创建时间,上次修改时间等。该程序的旧版本是用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年6月6日更新:

感谢所有建议尝试使用适当的时区偏移从UTC计算所需日期的人。在这个时候,我决定不值得这样做的风险。对于这个特定的业务需求,更好地说日期值不是您所期望的那样,因为这就是API的工作方式。如果我试图“修复”这个,那么我拥有它,而我宁愿不。

只是为了踢,我尝试通过互操作使用好的旧Scripting.FileSystemObject。它提供了与Windows资源管理器一致的预期结果,与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资源管理器的时间相差一小时。

再次感谢大家。

10 个答案:

答案 0 :(得分:4)

我可以在XP / Win2k3 / Vista上使用.NET 4.0和2.0 / 3.5重现这一点。

问题是DST现在处于不同的状态,而.NET正在以不同的方式处理这种差异,以及Scripting.FileSystemObject

(当DST与压缩文件时不同时,从zip文件中提取文件时,您会看到类似的问题。)

Via Reflector,.NET与非.NET代码路径不同的原因是IO.File(和IO.FileInfo)中的所有三个本地日期戳都被实现为获取Utc日期戳并应用{{1根据DST是否在Utc时间的本地时区中发生来确定要添加的偏移量。

我还检查了,通过将日期更改为去年7月1日,创建文件并查看当我返回当前日期(3月16日)的时间戳(我在南澳大利亚,所以我们现在在DST并且不是在7月1日),Windows(并且可能是.ToLocalTime)将DST添加到现在 NOW ,因此显示的时间实际上发生了变化。

因此,总而言之,.NET更为正确。

但是如果你想要不正确,但与资源管理器相同,请使用日期:

FileSystemObject

这已经在Raymond Chen's blog上进行了讨论(其中摘要是:.NET直观正确但不总是可逆的,Win32严格正确且可逆)。

答案 1 :(得分:1)

夏令时是我的罪魁祸首。 datDate包含我需要调整的时间,但只是检查“Now()”(或如上所示,没有参数是否相同)是DST,这就修复了它。

If TimeZone.CurrentTimeZone.IsDaylightSavingTime(Now()) = True Then
    datDate = DateAdd(DateInterval.Hour, -1, datDate)
End If

答案 2 :(得分:0)

尝试GetLastAccessTimeUtc因为我怀疑这是当地时间和夏令时的问题。

答案 3 :(得分:0)

嗯...我无法在Windows 7计算机上重现这一点,但这听起来像是一个节日问题。你可能会尝试类似的东西:

    Dim dt As DateTime = System.IO.File.GetLastAccessTime(FilePath)
    If Not dt.IsDaylightSavingTime() Then
        dt.AddHours(1)
    End If

可能需要进行实验,以确定是否加/减...

答案 4 :(得分:0)

如果使用当前文化格式化日期输出,您会得到什么?,例如,

Dim dt As DateTime = System.IO.File.GetLastAccessTime(FilePath)
Dim dateText As String = dt.ToString(System.Globalization.CultureInfo.CurrentCulture)

答案 5 :(得分:0)

答案 6 :(得分:0)

Public Function GetLastAccessTime(ByVal FilePath As String) As Date
    Return IO.File.GetLastAccessTime(FilePath).ToLocalTime()
End Function

答案 7 :(得分:0)

您可以使用以下代码检测偏移:

'...
Dim datetimeNow as DateTime = DateTime.Now
Dim localOffset as TimeSpan = datetimeNow - now.ToUniversalTime()
'...

将localOffset添加到您的时间

答案 8 :(得分:0)

VBA不允许使用时区,因此它必须使用Win API中的标准内容。我建议做实验:

  • 转到日期&时间属性,首先确保关闭夏令时并比较结果
  • 然后将时区更改为几个不同的时区,并查看两个应用程序的行为
  • 选择UTC时区,看看会发生什么

你上次访问的时间是否相同?

答案 9 :(得分:0)

我也遇到过这个问题,我相信我明白发生了什么。

我有一个Powershell脚本和一个CMD脚本(使用DIR命令),它报告修改的文件日期/时间。在最近从Daylight更改为标准时间之后,Powershell脚本将时间更改之前创建的文件的时间报告为比DIR命令晚一个小时。 Windows资源管理器与Powershell同时报告。

由于NTFS文件时间戳存储为UTC,因此它们被设置为显示/输出的本地时间。在显示时间时,DIR命令似乎使用UTC的当前时区偏移量(+8,因为我在太平洋时区,现在是标准时间),而Powershell(和Windows资源管理器)正在使用本地时间偏移在时间戳(创建文件时)时效果为UTC +7,因为它仍然是白天时间。

我认为Powershell转换是正确的。我想你可以争论任何一种方式,但是如果你看一下白天时间变化之前和之后的时间戳,那么Powershell结果会是相同的,而DIR结果会有所不同,而且不一致。