не удается преобразовать из FILETIME (время Windows) в dateTime (я получаю другую дату) - PullRequest
11 голосов
/ 21 мая 2011

Большинство файлов, которые я прочитал, получают правильное время при использовании следующего метода для преобразования:

// 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);
}

Здесь у меня есть пример в Visual Studio, чтобы показать, как этот метод иногда не работает, например, япокажет фактический файл на моем компьютере и отладку.Таким образом, файл, который находится в моей отладке:

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

А вот ФИЛЬТРАЦИЯ, которую я пытаюсь преобразовать в DateTime: «Мне нужен LastWriteTime, кстати»

enter image description here

Здесь вы можете увидетьчто dwHighDateTime = 30136437, а также что dwLowDateTime = -2138979250 из этого файла.

И когда я запускаю свой метод и другие методы, я получаю следующие даты: enter image description here

Пока что все кажетсяработать отлично.Но почему при просмотре и поиске этого конкретного файла в Windows я получаю другую дату?Вот дата, которую я получаю при просмотре свойств файла: enter image description here

Почему даты не совпадают?Что я делаю неправильно?

Ответы [ 5 ]

17 голосов
/ 21 мая 2011

Вам необходимо объединять значения LS и MS по битам, а не арифметически.

Попытка:

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

Или любое из следующего тоже должно работать:

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))

Вы можете избежать добавления по битам, а не поразрядно - или если вы уверены, что значения положительны (и не имеют общих битов). Но побитовый - или выражает намерение лучше.

7 голосов
/ 19 мая 2015

Я немного опоздал на вечеринку, но это сработало для меня надежно:

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);
        }
    }
}

Примечание : не доверяйте Windows Explorer.Используйте метод File.GetLastWriteTimeUtc , например, чтобы проверить, что файловая система на самом деле имеет против того, что возвращает этот метод расширения.В Explorer есть некоторые ошибки, которые не обновляют время файла в определенных ситуациях.Ура!:)

Примечание : для проверки необходимо использовать максимальные значения.Итак, предполагая dwHighDateTime = dwLowDateTime = UInt32.MaxValue = 4294967295 = 0xFFFFFFFF, следует, что (long)(((ulong)UInt32.MaxValue << 32) + UInt32.MaxValue) = -1 = 0xFFFFFFFFFFFFFFFF.К сожалению, ошибка в Windows API, по-видимому, заключается в том, что в конечном итоге время должно быть приведено к значению long, чтобы работать с ним для любых полезных приложений (поскольку большинство методов Windows API принимают время файла как longзначение), что означает, что как только старший бит становится высоким (1) на dwHighDateTime, значение становится отрицательным.Давайте попробуем с максимальным временем, не будучи высоким.Предполагая dwHighDateTime = Int32.MaxValue = 2147483647 = 0x7FFFFFFF и dwLowDateTime = UInt32.MaxValue = 4294967295 = 0xFFFFFFFF, из этого следует, что (long)(((ulong)Int32.MaxValue << 32) + UInt32.MaxValue) = 0x7FFFFFFFFFFFFFFF.

Примечание : 0x7FFFFFFFFFFFFFFF уже намного больше, чем DateTime.MaxValue.ToFileTimeUtc() = 2650467743999999999 = 0x24C85A5ED1C04000, делая такие большие числа уже бесполезными для любогопрактическое применение в .NET.

5 голосов
/ 20 июня 2012

Это еще один метод, который я видел для преобразования структуры FileTime в long (используя закодированный оператор в структуре), который затем можно легко преобразовать в DateTime с помощью функций DateTime.FromFileTime:

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;
    }
}
0 голосов
/ 21 мая 2011

Я попробовал следующее, и ни один из них не дал мне правильное время:
enter image description here

И я получил метод от здесь

0 голосов
/ 21 мая 2011

dwLowDateTime и dwHighDateTime должны быть uint, и похоже, что они int. Изменение этого, скорее всего, исправит это, хотя, как указал @Joe, вы все равно должны использовать | вместо +.

...