не удается конвертировать из FILETIME (windows time) в dateTime (я получаю другую дату)

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

// 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:UsersTonoDocumentsVisual Studio 2010проектыWpfApplication4WpfApplication4objx86DebugApp.г.в CS" enter image description here

а вот FILETIME, который я пытаюсь преобразовать в DateTime "мне нужно LastWriteTime кстати"

enter image description here

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

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

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

почему даты не совпадают? Что я делаю не так?

5 ответов


вам нужно объединить значения 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))

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


Это еще один метод, который я видел, чтобы преобразовать структуру 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;
    }
}

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

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. Использовать .GetLastWriteTimeUtc метод, например, чтобы проверить, что файловая система на самом деле имеет против того, что возвращает этот метод расширения. В проводнике есть некоторые ошибки, которые не обновляют время файла в определенных ситуациях. Ура! :)

Примечание: чтобы проверить это, вам нужно использовать максимальные значения. Итак, предполагая, что dwHighDateTime = dwLowDateTime = UInt32.MaxValue = 4294967295 = 0xFFFFFFFF, следует, что (long)(((ulong)UInt32.MaxValue << 32) + UInt32.MaxValue) = -1 = 0xFFFFFFFFFFFFFFFF. К сожалению, ошибка в API Windows, кажется, что в конечном итоге время должно быть приведено к long значение для работы с ним для любых полезных приложений (так как большинство методов Windows API принимают время файла как long value), что означает, что как только ведущий бит высок (1) on 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, рендеринг чисел, которые большие уже бесполезны для любых практических приложений.Сеть.


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

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


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