2011-01-05 12 views
11

Estoy trabajando en un programa que graba metadatos de fecha de archivos, como la hora de creación, la última hora de modificación, etc. Una versión anterior del programa está escrita en VBA, y hace algo como esto:IO.File.GetLastAccessTime está desactivado por una hora

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 

de salida para el archivo en cuestión:

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

Ese es el valor que recibo de las propiedades de los archivos de Windows detonador. Felicidad.

Estoy portando esta funcionalidad a una aplicación VB.Net. El nuevo código:

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

Simplicity itself. La salida:

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

Una hora más tarde.

Ambas funciones se están ejecutando en la misma máquina, verificando el mismo archivo. También intenté usar la clase IO.FileInfo con el mismo resultado. Revisé miles de archivos y se agotaron por una hora. Las otras propiedades de fecha para la hora de creación y la hora de la última modificación también están desactivadas en una hora.

¡Ayuda!

Olvidé mencionar en la publicación original, La zona horaria de la computadora es CST, y el horario de verano no está vigente.

He reproducido el problema en Windows 7 de 64 bits y Windows XP de 32 bits.

Gracias.

1/6/2011 actualización:

Gracias a todos los que sugirieron tratar de calcular la fecha deseada de la UTC usando las compensaciones de zona horaria correspondiente. En este momento, estoy decidiendo que no vale la pena el riesgo de hacerlo. Para este requisito de negocio en particular, es mucho mejor decir que el valor de la fecha no es el que esperabas porque así es como funciona la API. Si intento "arreglar" esto, entonces lo tengo, y preferiría no hacerlo.

Solo por las patadas que traté de utilizar el buen viejo Scripting.FileSystemObject a través de interoperabilidad. Proporciona los resultados esperados que coinciden con Windows Explorer, con una penalización de rendimiento de aproximadamente 5 veces en comparación con System.IO. Si resulta que debo obtener fechas que coincidan con lo que tiene Windows Explorer, voy a morder la bala y seguir esta ruta.

Otro experimento Probé iba directamente a la función API GetFileTime en Kernel32 a través de C#:

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

que resultó en exactamente el mismo comportamiento System.IO tenía, el tiempo estaba fuera por una hora desde el Explorador de Windows .

Gracias de nuevo a todos.

+2

Parece un problema con el horario de verano. – Flipster

+0

El último tiempo de acceso tiene una granularidad de aproximadamente 1 hora. Además, tenga en cuenta que, de forma predeterminada, en Windows Vista y en versiones anteriores, el [Valor de último acceso no se actualiza en volúmenes NTFS de manera predeterminada] (http://blogs.technet.com/b/filecab/archive/2006/11/07). /disabling-last-access-time-in-windows-vista-to-improve-ntfs-performance.aspx). –

+0

DST no está vigente ahora pero * estaba * en vigor cuando se modificó por última vez el archivo. ¿Quién tiene la razón? Trabaja en UTC para evitar tener que hacer esa pregunta. –

Respuesta

3

Puedo reproducir esto usando .NET 4.0 y 2.0/3.5 en XP/Win2k3/Vista.

El problema es que DST estaba en un estado diferente al actual, y .NET está procesando esta diferencia de manera diferente a Explorer y Scripting.FileSystemObject.

(Se puede ver un problema similar al extraer archivos de un archivo zip, cuando el horario de verano es diferente a cuando los archivos fueron cremallera.)

Via reflector, la razón .NET difiere de los caminos no es de código .NET que los tres sellos de fecha locales en IO.File (y IO.FileInfo) se implementan para obtener la marca de fecha Utc y aplicar .ToLocalTime, que determina el desplazamiento para agregar según si el horario de verano estaba sucediendo en la zona horaria local durante el tiempo Utc.

También revisé, cambiando la fecha al 1 de julio del año pasado, creando un archivo y mirando la marca de tiempo cuando regreso a la fecha actual (16 de marzo) (estoy en Australia del Sur, entonces estamos en DST ahora y no fueron el 1 de julio), y Windows (y presumiblemente FileSystemObject) agrega el horario de verano en el lugar AHORA por lo que la hora que se muestra realmente cambia.

Por lo tanto, en resumen, .NET es más correcto.

Pero si desea que el, el uso de fecha incorrecto, pero igual que el Explorador:

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

Esto ha sido discutido en Raymond Chen's blog (donde el resumen es: NET es intuitivamente correctos pero no siempre es invertible, y Win32 es estrictamente correcto e invertible).

0

Pruebe GetLastAccessTimeUtc ya que sospecho que esto es un problema de horario local y horario de verano.

0

Bueno ... No puedo reproducir eso en mi computadora con Windows 7, pero suena como un problema de ahorro de luz diurna.Se podría intentar algo como:

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

La experimentación puede ser necesaria en cuanto a si añadir/restar ...

+0

Se me olvidó mencionar en la publicación original: La zona horaria de la computadora es CST, y el horario de verano actualmente no está vigente. Gracias. –

+1

@Roger: ¿Qué sucede si usa SetLastAccessTime de VB.Net para establecer manualmente el valor en un archivo y luego leer el valor en VBA? ¿Visualizan VBA y Windows Explorer al mismo tiempo que el que configuraste en tu código? Podría ser una prueba interesante. – Peter

0

¿Qué se obtiene si se utiliza la cultura actual para dar formato a la salida de la fecha ?, por ejemplo,

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

¡Buena idea! Desafortunadamente, devolvió el mismo tiempo incorrecto que antes. –

0

Como ya se ha mencionado creo que la respuesta a esto es utilizar el tiempo UTC, y si lo que necesita saber a qué hora que es 'localmente' trabajo fuera del tiempo local basado en el horario de verano en ese particular punto en el tiempo utilizando la información cultural actual. No es muy trivial, ¿pero al menos funciona?

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

puede detectar el desplazamiento utilizando el siguiente código:

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

Añadir la localOffset a su tiempo

0

VBA no permite jugar con las zonas horarias lo que debe ser el uso de algo estándar a partir de Win API.Yo sugeriría experimento:

  • Ir a la fecha & propiedades de tiempo y el primero asegúrese de horario de verano está apagado y compara resultados
  • continuación, cambiar la zona horaria a varios diferentes y ver cómo las aplicaciones se comportan
  • seleccione UTC zona horaria y vea qué sucede

¿Alguna vez recibirá la misma hora de último acceso?

1

El horario de verano fue el culpable para mí. datDate contiene el tiempo que necesito para ajustar, pero simplemente verifica si "Now()" (o como se muestra arriba, ningún parámetro hace lo mismo) es DST, esto lo solucionó.

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

Sé casi que en ninguna parte tiene una compensación de ahorro de luz diurna de más de 1 hora, pero eso combinado con el '= True' y casi he hecho clic -1 varias veces al mirar esto ... –

0

me encontré con este problema también, y creo que entiendo lo que está pasando.

Tengo un script Powershell y un script CMD (usando el comando DIR) que informa la fecha/hora modificada de los archivos. Después del cambio reciente de Daylight a la hora estándar, la secuencia de comandos de Powershell informaba que la hora de los archivos creados antes del cambio de hora era una hora más tarde que el comando DIR. Windows Explorer informó al mismo tiempo que Powershell.

Dado que las marcas de tiempo de los archivos NTFS se almacenan como UTC, se envían a la hora local para visualización/salida. Parece que el comando DIR utiliza el desplazamiento de zona horaria actual desde UTC al mostrar la hora (+8, ya que estoy en la zona horaria del Pacífico y ahora es la hora estándar), mientras que Powershell (y Windows Explorer) está utilizando el desfase horario local ESTABA EN EFECTO en el momento de la marca de tiempo (cuando se crearon los archivos), que era UTC +7, ya que todavía era de día.

Creo que la conversión de Powershell es correcta. Supongo que puede argumentar de cualquier manera, pero si mira la marca de tiempo antes y después de un cambio de horario de verano, los resultados de Powershell serían los mismos, mientras que los resultados de DIR serían diferentes e inconsistentes.

Cuestiones relacionadas