无法从FILETIME(窗口时间)转换为dateTime(我得到一个不同的日期)

时间:2011-05-21 18:45:15

标签: c# datetime datetime-format filetime

使用以下方法进行转换时,我读到的大多数文件都是合适的时间:

// 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的FILETIME“顺便说一下我需要LastWriteTime”

enter image description here

在这里,您可以看到dwHighDateTime = 30136437以及该文件中的dwLowDateTime = -2138979250。

当我运行我的方法加上其他技术时,我得到以下日期: enter image description here

所以到目前为止,一切似乎都很有效。但是为什么当我在Windows中浏览并查找特定文件时,我会得到一个不同的日期!这是我在查看文件属性时得到的日期: enter image description here

为什么日期不匹配?我究竟做错了什么?

5 个答案:

答案 0 :(得分:16)

您需要按位组合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))

你可以通过添加而不是按位来逃避 - 或者如果你确定值是正的(并且没有共同的位)。但是按位 - 或更好地表达意图。

答案 1 :(得分:7)

我参加派对有点晚了,但这对我来说是可靠的:

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资源管理器。例如,使用File.GetLastWriteTimeUtc方法验证文件系统实际上对此扩展方法返回的内容。资源管理器中存在一些错误,在某些情况下不会更新文件时间。干杯! :)

注意:要对此进行测试,您需要使用最大值。因此,假设dwHighDateTime = dwLowDateTime = UInt32.MaxValue = 4294967295 = 0xFFFFFFFF,它遵循(long)(((ulong)UInt32.MaxValue << 32) + UInt32.MaxValue) = -1 = 0xFFFFFFFFFFFFFFFF。不幸的是,Windows API中的谬误似乎是最终需要将时间转换为long值,以便为任何有用的应用程序使用它(因为大多数Windows API方法将文件时间视为{ {1}}值),这意味着一旦long上的前导位为高(1),该值就变为负值。让我们尝试最大时间不高。假设dwHighDateTimedwHighDateTime = Int32.MaxValue = 2147483647 = 0x7FFFFFFF,则遵循dwLowDateTime = UInt32.MaxValue = 4294967295 = 0xFFFFFFFF

注意(long)(((ulong)Int32.MaxValue << 32) + UInt32.MaxValue) = 0x7FFFFFFFFFFFFFFF已经比0x7FFFFFFFFFFFFFFF大得多,渲染数量已经无法用于.NET中的任何实际应用程序。

答案 2 :(得分:5)

这是我看到的将FileTime结构转换为long(使用struct中的编码运算符)的另一种方法,然后可以使用DateTime.FromFileTime函数轻松地将其转换为DateTime:

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 :(得分:0)

dwLowDateTimedwHighDateTime应为uint,看起来好像是int。改变这种情况很可能会解决这个问题,因为@Joe指出你仍然应该使用|代替+

答案 4 :(得分:0)

我尝试了以下内容,并且没有给我正确的时间:
enter image description here

我从here

获得了方法