2011-01-05 6 views
11

Ich arbeite an einem Programm, das Datum Metadaten von Dateien, wie Erstellungszeit, Zeitpunkt der letzten Änderung, etc. Eine alte Version des Programms wird in VBA geschrieben, und tut etwas wie folgt aus:IO.File.GetLastAccessTime ist um eine Stunde

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 

Ausgang für die betreffende Datei:

?getfilelastaccesstime("SomePath") 
7/30/2010 2:16:07 PM 

, dass der Wert I aus den Dateieigenschaften in Windows Exploder erhalten ist. Glück.

Ich portiere diese Funktionalität in eine VB.Net App. Der neue Code:

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

Einfachheit selbst. Der Ausgang:

?GetLastAccessTime("SomePath") 
#7/30/2010 3:16:07 PM# 

Eine Stunde später.

Beide Funktionen laufen auf demselben Computer und überprüfen die gleiche Datei. Ich habe auch versucht, die Klasse IO.FileInfo mit dem gleichen Ergebnis zu verwenden. Ich habe Tausende von Dateien überprüft und sie sind alle um eine Stunde ausgeschaltet. Die anderen Datumseigenschaften für die Erstellungszeit und die Zeit für die letzte Änderung sind ebenfalls um eine Stunde abgelaufen.

Hilfe!

Ich habe vergessen, im ursprünglichen Beitrag zu erwähnen, Die Zeitzone des Computers ist CST, und Sommerzeit ist derzeit nicht wirksam.

Ich habe das Problem auf Windows 7 64 Bit und Windows XP 32 Bit reproduziert.

Danke.

2011.01.06 Update:

Dank an alle, die das gewünschte Datum aus UTC unter Verwendung der entsprechenden Zeitzone Offsets zu berechnen vorgeschlagen versuchen. Zu dieser Zeit bin ich der Meinung, dass es das Risiko nicht wert ist, dies zu tun. Für diese spezielle Geschäftsanforderung ist es viel besser zu sagen, dass der Datumswert nicht das ist, was Sie erwartet haben, weil das genau die Art ist, wie die API funktioniert. Wenn ich versuche, das zu "reparieren", dann besitze ich es, und das möchte ich lieber nicht.

Nur für Kicks habe ich versucht, die gute alte Scripting.FileSystemObject über Interop. Es gibt die erwarteten Ergebnisse, die mit Windows Explorer übereinstimmen, mit etwa 5-facher Leistungseinbußen im Vergleich zu System.IO. Wenn es sich herausstellt, dass ich Daten bekommen muss, die dem entsprechen, was Windows Explorer hat, werde ich in den sauren Apfel beißen und diesen Weg gehen.

Ein weiteres Experiment versuchte ich würde direkt an die Funktion GetFileTime API in kernel32 über C#:

[DllImport("kernel32.dll", SetLastError = true)] 
private static extern bool GetFileTime(
IntPtr hFile, 
ref FILETIME lpCreationTime, 
ref FILETIME lpLastAccessTime, 
ref FILETIME lpLastWriteTime 
); 

, die in genau dem gleichen Verhalten führte System.IO hatte, war die Zeit weg von einer Stunde aus dem Windows Explorer .

Nochmals vielen Dank.

+2

Sieht aus wie ein Problem mit der Sommerzeit für mich – Flipster

+0

Last Access Time hat eine Granularität von ca. 1 Stunde. Beachten Sie außerdem, dass der Wert für die letzte Zugriffszeit in Windows Vista und höher standardmäßig nicht auf NTFS-Volumes aktualisiert wird (http://blogs.technet.com/b/filecab/archive/2006/11/07) /disabling-last-access-time-in-windows-vista-to-improve-ntfs-performance.aspx). –

+0

DST ist jetzt nicht wirksam, aber * * war wirksam, als die Datei zuletzt geändert wurde. Wer hat Recht? Arbeiten Sie in UTC, um diese Frage nicht stellen zu müssen. –

Antwort

3

Ich kann dies mit .NET 4.0 und 2.0/3.5 auf XP/Win2k3/Vista reproduzieren.

Das Problem ist DST war in einem anderen Zustand als jetzt, und .NET verarbeitet diesen Unterschied anders Explorer und Scripting.FileSystemObject.

(Sie können ein ähnliches Problem sehen, wenn Dateien aus einer ZIP-Datei zu extrahieren, wenn DST anders ist, wenn die Dateien waren mit Reißverschluss.)

Via Reflektor, der Grund .NET unterscheidet sich von den nicht .NET Code-Pfade ist dass alle drei lokalen Datumsstempel in IO.File (und IO.FileInfo) so implementiert sind, dass sie den Utc-Datumsstempel erhalten und .ToLocalTime anwenden, wodurch bestimmt wird, welcher Offset hinzugefügt werden soll, abhängig davon, ob DST in der lokalen Zeitzone für die Utc-Zeit stattfand.

Ich überprüfte auch, indem ich das Datum auf den 1. Juli letzten Jahres änderte, eine Datei erstellte und den Zeitstempel beobachtete, wenn ich zum aktuellen Datum (16. März) zurückkehrte (ich bin in South Australia, also in DST jetzt und war nicht am 1. Juli), und Windows (und vermutlich FileSystemObject) fügt die DST an Stelle NOW hinzu, so ändert sich die angezeigte Zeit tatsächlich.

Also, zusammenfassend ist .NET richtiger.

Aber wenn Sie die falsche wollen, aber gleiche wie Explorer, Datum Verwendung:

Public Function GetLastAccessTime(ByVal FilePath As String) As Date 
    Return IO.File.GetLastAccessTimeUtc(FilePath) _ 
     .Add(TimeZone.CurrentTimeZone.GetUtcOffset(Now)) 
End Function 

Dies wird auf Raymond Chen's blog diskutiert worden (wo die Zusammenfassung: NET ist intuitiv richtig, aber nicht immer umkehrbar, und Win32 ist streng korrekt und invertierbar).

0

Versuchen Sie GetLastAccessTimeUtc, da ich vermute, dass dies ein Problem der lokalen Zeit und Sommerzeit ist.

0

Nun ... Ich kann das nicht auf meinem Windows 7 Computer reproduzieren, aber es klingt wie ein Day-Light-Spar-Problem.Sie könnten versuchen, so etwas wie:

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

Experimentation darüber erforderlich werden kann, ob addieren/subtrahieren ...

+0

Ich habe vergessen, im ursprünglichen Beitrag zu erwähnen, Die Zeitzone des Computers ist CST, und die Sommerzeit ist derzeit nicht wirksam. Vielen Dank. –

+1

@Roger - Was passiert, wenn Sie SetLastAccessTime von VB.Net verwenden, um den Wert manuell für eine Datei festzulegen und dann den Wert in VBA zu lesen? Zeigen VBA und Windows Explorer die gleiche Zeit wie die, die Sie in Ihrem Code festgelegt haben? Könnte ein interessanter Test sein. – Peter

0

Was tun Sie, wenn Sie die aktuelle Kultur verwenden das Datum Ausgabe zu formatieren ?, zB

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

Ordentliche Idee! Leider gab es dieselbe falsche Zeit wie zuvor. –

0

Wie bereits erwähnt ich denke, die Antwort auf diese Frage ist die UTC-Zeit zu verwenden, und wenn Sie wissen müssen, was Zeit, die ‚vor Ort‘ trainieren die lokale Zeit auf der Sommerzeit an diesem speziellen basiert Zeitpunkt mit den aktuellen Kulturinformationen. Nicht ganz trivial, aber zumindest ein Workaround?

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

Sie können die mit dem folgenden Code-Offset erkennen:

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

Fügen Sie die localOffset zu Ihrer Zeit

0

VBA nicht erlaubt, mit Zeitzonen Geige, damit es etwas Standard von Win-API sein müssen.Ich würde Experiment vorschlagen:

  • Gehe zu Datum & Zeiteigenschaften und zuerst sicher Sommerzeit machen ausgeschaltet ist und die Ergebnisse vergleichen
  • dann Zeitzone mehrere unterschiedliche ändern und sehen, wie beide Anwendungen verhalten
  • UTC wählen Zeitzone und sehen, was passiert

Werden Sie jemals die gleiche zuletzt abgerufene Zeit bekommen?

1

Sommerzeit war der Schuldige für mich. datDate enthielt die Zeit, die ich anpassen musste, aber einfach zu überprüfen, ob "Now()" (oder wie oben gezeigt, kein Parameter macht das Gleiche) DST ist, dies wurde behoben.

+0

Ich weiß fast nirgends hat eine Sommerzeit Offset von anderen als 1 Stunde, aber das kombiniert mit der '= True' und ich habe fast ein paar Mal geklickt -1, wenn man sich das anschaut ... –

0

Ich habe dieses Problem auch, und ich glaube, ich verstehe, was passiert.

Ich habe ein Powershell-Skript und ein CMD-Skript (mit dem DIR-Befehl), die das geänderte Datum/Uhrzeit von Dateien meldet. Nach der letzten Änderung von Daylight auf Standardzeit hat das Powershell-Skript die Zeit der Dateien, die vor der Zeitänderung erstellt wurden, eine Stunde nach dem DIR-Befehl gemeldet. Der Windows Explorer meldet dieselbe Zeit wie Powershell.

Da die Zeitstempel der NTFS-Datei als UTC gespeichert sind, werden sie zur lokalen Zeit für die Anzeige/Ausgabe übernommen. Es scheint, dass der DIR-Befehl den aktuellen Zeitzonen-Offset von UTC verwendet, wenn die Zeit angezeigt wird (+8, da ich in der Pacific-Zeitzone bin und jetzt Standardzeit ist), während Powershell (und Windows Explorer) den lokalen Zeitoffset verwendet Das war zum Zeitpunkt des Zeitstempels (als die Dateien erstellt wurden) in EFFEKT, was UTC +7 war, da es noch Tageslicht war.

Ich denke, dass die Powershell-Konvertierung korrekt ist. Ich nehme an, Sie können in beide Richtungen argumentieren, aber wenn Sie sich den Zeitstempel vor und nach einer Änderung der Sommerzeit ansehen, wären die Powershell-Ergebnisse gleich, während die DIR-Ergebnisse anders und inkonsistent wären.

Verwandte Themen