【问题标题】:not being able to convert from FILETIME (windows time) to dateTime ( I get a different date )无法从 FILETIME(Windows 时间)转换为 dateTime(我得到不同的日期)
【发布时间】:2011-08-30 08:04:06
【问题描述】:

我阅读的大部分文件在使用以下方法进行转换时得到了正确的时间:

// 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"

这是我试图转换为 DateTime 的 FILETIME “顺便说一下,我需要 LastWriteTime”

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

当我运行我的方法和其他技术时,我得到以下日期:

到目前为止,一切似乎都运行良好。但是,为什么当我在 Windows 中浏览并查找该特定文件时,我得到了不同的日期!?这是我看到文件属性时得到的日期:

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

【问题讨论】:

  • 你为什么要这么辛苦?好像你几乎重写了 FileInfo 类...msdn.microsoft.com/en-us/library/system.io.fileinfo.aspx
  • 我不知道为什么 OP 这样做很难。当使用长路径名时,即超过 [MAX_LENGTH] = 260 字节的路径,您将需要重写大部分 System.IO 以使用非托管代码。在这里可以找到更多信息:blogs.msdn.com/b/bclteam/archive/2007/02/13/…
  • 使用 FILETIME / GetFileTime 代替 FileInfo 有一些合法的场景:例如,如果您想获取有关已打开其句柄的文件的统计信息(并且在某些情况下无法通过 FileInfo 重新打开它)原因)

标签: c# datetime datetime-format filetime


【解决方案1】:

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

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

【讨论】:

  • time.dwLowDateTime 显示为负值(不应该如此),因此将其转换为 long 会产生不正确的结果。相反 IIRC,您需要执行 (long)((uint)(time.dwLowDateTime)) 或修复互操作,使其以 uint 开始。
  • 很累但没有工作。我认为我的方法是读取错误日期的方法。我会继续努力弄明白的。
【解决方案2】:

我参加聚会有点晚了,但这对我来说确实有效:

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 &lt;&lt; 32) + UInt32.MaxValue) = -1 = 0xFFFFFFFFFFFFFFFF。不幸的是,Windows API 中的谬误似乎是最终需要将时间转换为 long 值,以便将其用于任何有用的应用程序(因为大多数 Windows API 方法将文件时间作为 long值),这意味着一旦dwHighDateTime 的前导位为高(1),该值变为负数。让我们尝试不高的最长时间。假设dwHighDateTime = Int32.MaxValue = 2147483647 = 0x7FFFFFFFdwLowDateTime = UInt32.MaxValue = 4294967295 = 0xFFFFFFFF,那么(long)(((ulong)Int32.MaxValue &lt;&lt; 32) + UInt32.MaxValue) = 0x7FFFFFFFFFFFFFFF

注意0x7FFFFFFFFFFFFFFF 已经比 DateTime.MaxValue.ToFileTimeUtc() = 2650467743999999999 = 0x24C85A5ED1C04000 大得多,呈现的数字对于 .NET 中的任何实际应用程序来说已经无用。

【讨论】:

  • 这个解决方案对我有用,而其他答案返回不正确的结果
  • @DavidRoberts 那是因为其他答案没有将高日期时间组件作为无符号 64 位值考虑在内...相反,我看到它们错误地转换为有符号 64 位值,它可以返回一个否定的结果,这是不正确的。
  • 确实这似乎是最准确的解决方案。
【解决方案3】:

这是我见过的另一种将 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;
    }
}

【讨论】:

    【解决方案4】:

    我已经尝试了以下方法,但没有一个能帮到我:

    我从here得到了方法

    【讨论】:

    • 大家都找到解决方法了吗?
    【解决方案5】:

    dwLowDateTimedwHighDateTime 应该是 uint,看起来它们是 int。更改此设置很可能会解决此问题,但正如 @Joe 指出的那样,您仍应使用 | 而不是 +

    【讨论】:

      猜你喜欢
      • 2014-10-03
      • 2017-01-21
      • 1970-01-01
      • 2011-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-21
      • 1970-01-01
      相关资源
      最近更新 更多