我正在开发一个记录文件中日期元数据的程序,例如创建时间,上次修改时间等。该程序的旧版本是用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资源管理器的时间相差一小时。
再次感谢大家。
答案 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中的标准内容。我建议做实验:
你上次访问的时间是否相同?
答案 9 :(得分:0)
我也遇到过这个问题,我相信我明白发生了什么。
我有一个Powershell脚本和一个CMD脚本(使用DIR命令),它报告修改的文件日期/时间。在最近从Daylight更改为标准时间之后,Powershell脚本将时间更改之前创建的文件的时间报告为比DIR命令晚一个小时。 Windows资源管理器与Powershell同时报告。
由于NTFS文件时间戳存储为UTC,因此它们被设置为显示/输出的本地时间。在显示时间时,DIR命令似乎使用UTC的当前时区偏移量(+8,因为我在太平洋时区,现在是标准时间),而Powershell(和Windows资源管理器)正在使用本地时间偏移在时间戳(创建文件时)时效果为UTC +7,因为它仍然是白天时间。
我认为Powershell转换是正确的。我想你可以争论任何一种方式,但是如果你看一下白天时间变化之前和之后的时间戳,那么Powershell结果会是相同的,而DIR结果会有所不同,而且不一致。