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

Ton*_*Nam 11 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);
}
Run Code Online (Sandbox Code Playgroud)

这里我在visual studio中有一个例子来说明这个方法有时不起作用,例如我将在我的计算机和调试中显示实际文件.所以恰好在我的调试中的文件是:

"A:\ Users\Tono\Documents\Visual Studio 2010\Projects\WpfApplication4\WpfApplication4\obj\x86\Debug\App.g.cs" 在此输入图像描述

这里是我试图转换为DateTime的FILETIME"我需要LastWriteTime"

在此输入图像描述

在这里你可以看到dwHighDateTime = 30136437以及该文件中的dwLowDateTime = -2138979250.

当我运行我的方法加上其他技术时,我得到以下日期: 在此输入图像描述

所以到目前为止,一切似乎都很有效.但是为什么当我在Windows中浏览并查找特定文件时,我会得到一个不同的日期!这是我在查看文件属性时得到的日期: 在此输入图像描述

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

Joe*_*Joe 17

您需要按位组合LS和MS值,而不是算术.

尝试:

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

或者以下任何一项也应该有效:

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))
Run Code Online (Sandbox Code Playgroud)

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


Ale*_*dru 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:不要信任Windows资源管理器.例如,使用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 = 0x7FFFFFFFdwLowDateTime = UInt32.MaxValue = 4294967295 = 0xFFFFFFFF,它遵循(long)(((ulong)Int32.MaxValue << 32) + UInt32.MaxValue) = 0x7FFFFFFFFFFFFFFF.

注意:0x7FFFFFFFFFFFFFFF已经大得多DateTime.MaxValue.ToFileTimeUtc() = 2650467743999999999 = 0x24C85A5ED1C04000,渲染数量已经无法用于.NET中的任何实际应用程序.

  • 此解决方案适用于我,而其他答案返回不正确的结果 (2认同)
  • @DavidRoberts那是因为其他答案没有将高日期时间组件作为无符号64位值考虑在内......相反,我看到它们错误地转换为有符号64位值,这可能返回负结果,这是不正确的。 (2认同)

mki*_*acs 5

这是我见过的将FileTime结构转换为long(使用结构中的编码运算符)的另一种方法,然后可以使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)