2011-05-21 14 views
8

La mayoría de los archivos que leí llegar el momento adecuado cuando se utiliza el método siguiente para convertir:no ser capaz de convertir de FILETIME (ventanas de tiempo) a fechaHora (me da una fecha diferente)

// works great most of the time 
private static DateTime convertToDateTime(System.Runtime.InteropServices.ComTypes.FILETIME time) 
{ 
    long highBits = time.dwHighDateTime; 
    highBits = highBits << 32; 
    return DateTime.FromFileTimeUtc(highBits + time.dwLowDateTime); 
} 

Aquí tener un ejemplo en Visual Studio para mostrar cómo este método a veces no funciona, por ejemplo, mostraré el archivo real en mi computadora y la depuración. Por lo que el archivo que pasa a ser en mi depuración es:

"A: \ Users \ Tono \ Documents \ Visual Studio 2010 \ Projects \ WpfApplication4 \ WpfApplication4 \ obj \ x86 \ Debug \ App.g.cs" enter image description here

y aquí es el FILETIME que estoy tratando de convertir a DateTime "necesito el LastWriteTime por cierto"

enter image description here

aquí se puede ver que dwHighDateTime = 30136437 y también que dwLowDateTime = -2138979250 de ese archivo.

Y cuando corro mi método más otras técnicas consigo las siguientes fechas: enter image description here

Así que hasta ahora todo parece estar funcionando muy bien. Pero ¿por qué eso es que cuando navego y busco ese archivo específico en Windows obtengo una fecha diferente? Aquí está la fecha que recibo al ver las propiedades del archivo: enter image description here

¿Por qué las fechas no coinciden? ¿Qué estoy haciendo mal?

+2

¿Por qué estás haciendo esto de la manera difícil? Parece que estás reescribiendo bastante la clase FileInfo ... http://msdn.microsoft.com/en-us/library/system.io.fileinfo.aspx –

+0

No estoy seguro de por qué el OP está haciendo esto de la manera difícil . Cuando trabaje con nombres de ruta larga, es decir, rutas de más de [MAX_LENGTH] = 260 bytes, necesitará _ reescribir la mayor parte de System.IO para usar código no administrado. Puede encontrar más información aquí: http://blogs.msdn.com/b/bclteam/archive/2007/02/13/long-paths-in-net-part-1-of-3-kim-hamilton .aspx –

+0

Existen situaciones legítimas para usar FILETIME/GetFileTime en lugar de FileInfo: por ejemplo, si desea obtener estadísticas sobre un archivo cuyo identificador ya tiene abierto (y no puede volver a abrirlo a través de FileInfo por algún motivo) –

Respuesta

15

Necesita combinar los valores LS y MS en modo bit, no aritméticamente.

Probar:

 ulong high = 30136437; 
     unchecked 
     { 
      int low = -2138979250; 
      uint uLow = (uint)low; 
      high = high << 32; 
      Date dt = DateTime.FromFileTime((long) (high | (ulong)uLow)); 
     } 

o cualquiera de lo siguiente debe funcionar también:

long highBits = time.dwHighDateTime;  
highBits = highBits << 32;  

return DateTime.FromFileTimeUtc(highBits + (long) (uint) time.dwLowDateTime); 

return DateTime.FromFileTimeUtc(highBits | (long) (uint) time.dwLowDateTime); 

return DateTime.FromFileTimeUtc(highBits + ((long)low & 0xFFFFFFFF)) 

return DateTime.FromFileTimeUtc(highBits | ((long)low & 0xFFFFFFFF)) 

Usted puede salirse con la adición en lugar de un bit a bit, o si está seguro de los valores son positivos (y no tienen bits en común). Pero a nivel de bit, o expresa mejor la intención.

+1

time. dwLowDateTime aparece como un valor negativo (no debería ser así), por lo que lanzarlo por mucho tiempo dará un resultado incorrecto. en su lugar, IIRC debe hacer '(largo) ((uint) (time.dwLowDateTime))' o arreglar la interoperabilidad para que comience como una uint. – Yaur

+0

cansado pero no funcionó. Creo que mi método es el que está leyendo la fecha incorrecta. Seguiré tratando de resolverlo. –

0

dwLowDateTime y dwHighDateTime debe ser uint y parece que son int. Sin embargo, cambiar esto probablemente lo arregle, ya que @Joe señaló que aún debería usar | en lugar de +.

0

He intentado lo siguiente y no de ellos me llegar el momento adecuado:
enter image description here

Y tengo el método de here

+0

¿Alguna vez encontraron la solución para esto? –

5

Este es otro método que he visto para convertir una estructura FileTime a largo (usando un operador codificado en la estructura), que luego se puede convertir fácilmente a DateTime usando DateTime.FromFileTime funciones:

public struct FileTime 
{ 
    public uint dwLowDateTime; 
    public uint dwHighDateTime; 

    public static implicit operator long(FileTime fileTime) 
    { 
     long returnedLong; 
     // Convert 4 high-order bytes to a byte array 
     byte[] highBytes = BitConverter.GetBytes(fileTime.dwHighDateTime); 
     // Resize the array to 8 bytes (for a Long) 
     Array.Resize(ref highBytes, 8); 

     // Assign high-order bytes to first 4 bytes of Long 
     returnedLong = BitConverter.ToInt64(highBytes, 0); 
     // Shift high-order bytes into position 
     returnedLong = returnedLong << 32; 
     // Or with low-order bytes 
     returnedLong = returnedLong | fileTime.dwLowDateTime; 
     // Return long 
     return returnedLong; 
    } 
} 
3

estoy un poco tarde a la fiesta, pero esto ha funcionado de forma fiable para mí:

public static class FILETIMEExtensions 
{ 
    public static DateTime ToDateTime(this System.Runtime.InteropServices.ComTypes.FILETIME time) 
    { 
     ulong high = (ulong)time.dwHighDateTime; 
     uint low = (uint)time.dwLowDateTime; 
     long fileTime = (long)((high << 32) + low); 
     try 
     { 
      return DateTime.FromFileTimeUtc(fileTime); 
     } 
     catch 
     { 
      return DateTime.FromFileTimeUtc(0xFFFFFFFF); 
     } 
    } 
} 

Nota: No confiar en el Explorador de Windows. Use el método File.GetLastWriteTimeUtc, por ejemplo, para verificar lo que el sistema de archivos realmente tiene contra lo que devuelve este método de extensión. Explorer tiene algunos errores que no actualizan los tiempos de archivo en ciertas situaciones. ¡Aclamaciones! :)

Nota: Para probar esto, necesita utilizar valores máximos. Entonces, asumiendo dwHighDateTime = dwLowDateTime = UInt32.MaxValue = 4294967295 = 0xFFFFFFFF, se deduce que (long)(((ulong)UInt32.MaxValue << 32) + UInt32.MaxValue) = -1 = 0xFFFFFFFFFFFFFFFF. Desafortunadamente, la falacia en la API de Windows parece ser que eventualmente el tiempo necesita ser convertido a un valor long para trabajar con él para cualquier aplicación útil (ya que la mayoría de los métodos API de Windows toman el tiempo del archivo como un valor long), significa que una vez que el bit de entrada es alto (1) en dwHighDateTime, el valor se vuelve negativo. Probemos con el tiempo máximo no siendo alto. Suponiendo dwHighDateTime = Int32.MaxValue = 2147483647 = 0x7FFFFFFF y dwLowDateTime = UInt32.MaxValue = 4294967295 = 0xFFFFFFFF, se deduce que (long)(((ulong)Int32.MaxValue << 32) + UInt32.MaxValue) = 0x7FFFFFFFFFFFFFFF.

Nota: 0x7FFFFFFFFFFFFFFF ya es mucho más grande que DateTime.MaxValue.ToFileTimeUtc() = 2650467743999999999 = 0x24C85A5ED1C04000, números tan grandes que ya inútiles para cualquier aplicaciones prácticas en la prestación de .NET.

+0

Esta solución funciona para mí, mientras que las otras respuestas devuelven resultados incorrectos –

+0

@DavidRoberts Eso es porque otras respuestas no tienen en cuenta que el componente de fecha alta como un valor de 64 bits sin firmar ... en cambio, veo que se transfieren incorrectamente a un firmado Valor de 64 bits, que puede devolver un resultado negativo, que es incorrecto. – Alexandru

Cuestiones relacionadas