在 Unix/Linux 中将 Windows 文件时间转换为秒

Posted

技术标签:

【中文标题】在 Unix/Linux 中将 Windows 文件时间转换为秒【英文标题】:Convert Windows Filetime to second in Unix/Linux 【发布时间】:2011-09-03 22:37:45 【问题描述】:

我有一个跟踪文件,每个事务时间都以 Windows 文件时间格式表示。这些时间数字是这样的:

128166372003061629 128166372016382155 128166372026382245

请告诉我 Unix/Linux 中是否有任何 C/C++ 库可以从这些数字中提取实际时间(特别是秒)?我可以编写自己的提取函数吗?

【问题讨论】:

【参考方案1】:

这很简单:windows epoch 从 1601-01-01T00:00:00Z 开始。它比 UNIX/Linux 纪元 (1970-01-01T00:00:00Z) 早 11644473600 秒。 Windows 滴答声以 100 纳秒为单位。因此,从 UNIX 纪元获取秒数的函数如下:

#define WINDOWS_TICK 10000000
#define SEC_TO_UNIX_EPOCH 11644473600LL

unsigned WindowsTickToUnixSeconds(long long windowsTicks)

     return (unsigned)(windowsTicks / WINDOWS_TICK - SEC_TO_UNIX_EPOCH);

【讨论】:

请注意,11644473600 不计算闰秒。 另见Does the windows FILETIME structure include leap seconds? (@DietrichEpp) 请注意,Windows 可以表示超出 POSIX 纪元时间范围的时间,因此转换例程应适当返回“超出范围”指示。最简单的方法是:`long long secs; time_t t; secs = (windowsTicks / WINDOWS_TICK - SEC_TO_UNIX_EPOCH); t = (time_t) 秒; if (secs != (long long) t) 返回 (time_t) -1;返回 t; ` @Dietrich epp。闰秒是在 1972 年引入的。因此在 1601 年和 1970 年之间没有闰秒,因此与这种转换无关。 我必须做同样的事情,但我发现您可能将这些数字作为字符串提取出来。如果是这种情况,您可以去掉最后 7 位数字。【参考方案2】:

FILETIME 类型是自 1601 年 1 月 1 日以来增量为 100 ns 的数字。

要将其转换为 unix time_t,您可以使用以下内容。

#define TICKS_PER_SECOND 10000000
#define EPOCH_DIFFERENCE 11644473600LL
time_t convertWindowsTimeToUnixTime(long long int input)
    long long int temp;
    temp = input / TICKS_PER_SECOND; //convert from 100ns intervals to seconds;
    temp = temp - EPOCH_DIFFERENCE;  //subtract number of seconds between epochs
    return (time_t) temp;

然后您可以使用 ctime 函数对其进行操作。

【讨论】:

注意这里的间隔不计算闰秒。 @Dietrich epp。闰秒是在 1972 年引入的。因此在 1601 年和 1970 年之间没有闰秒,因此与这种转换无关。【参考方案3】:

(我发现我无法在评论中输入可读代码,所以...)

请注意,Windows 可以表示超出 POSIX 纪元时间范围的时间,因此转换例程应适当返回“超出范围”指示。最简单的方法是:

   ... (as above)
   long long secs;
   time_t t;

   secs = (windowsTicks / WINDOWS_TICK - SEC_TO_UNIX_EPOCH);
   t = (time_t) secs;
   if (secs != (long long) t)    // checks for truncation/overflow/underflow
      return (time_t) -1;   // value not representable as a POSIX time
   return t;

【讨论】:

【参考方案4】:

旧问题的新答案。

使用 C++11 的 <chrono> 以及这个免费的开源库:

https://github.com/HowardHinnant/date

可以很容易地将这些时间戳转换为std::chrono::system_clock::time_point,并将这些时间戳转换为公历中人类可读的格式:

#include "date.h"
#include <iostream>

std::chrono::system_clock::time_point
from_windows_filetime(long long t)

    using namespace std::chrono;
    using namespace date;
    using wfs = duration<long long, std::ratio<1, 10'000'000>>;
    return system_clock::time_pointfloor<system_clock::duration>(wfst -
                        (sys_days1970_y/jan/1 - sys_days1601_y/jan/1));


int
main()

    using namespace date;
    std::cout << from_windows_filetime(128166372003061629) << '\n';
    std::cout << from_windows_filetime(128166372016382155) << '\n';
    std::cout << from_windows_filetime(128166372026382245) << '\n';

对我来说这个输出:

2007-02-22 17:00:00.306162
2007-02-22 17:00:01.638215
2007-02-22 17:00:02.638224

在 Windows 上,您实际上可以跳过floor,并获得最后一位十进制数字的精度:

    return system_clock::time_pointwfst -
                        (sys_days1970_y/jan/1 - sys_days1601_y/jan/1);

2007-02-22 17:00:00.3061629
2007-02-22 17:00:01.6382155
2007-02-22 17:00:02.6382245

启用优化后,子表达式 (sys_days1970_y/jan/1 - sys_days1601_y/jan/1) 将在编译时转换为 days134774,这将进一步在编译时转换为完整表达式所需的任何单位(秒、100 纳秒等)。底线:这既可读又高效。

【讨论】:

date.h 库的问题,即字面意思只是从您的 GIT 存储库中复制 data.h 文件并包含它,对吗?我在问,因为如果我这样做,我会在 data.h 中得到一个编译错误date.h(3832): error C2059: syntax error: '' 如果我不使用 date.h,那么与上面代码的唯一区别就是使用 seconds 11644473600LL 而不是 (sys_days1970_y/jan/1 - sys_days1601_y/jan/1),对吗? 感谢您的报告。看起来 VS 将 &lt; 误解为开放模板令牌而不是小于令牌。我刚刚推送了一个修复程序。你能再试一次吗?固定行是 3689,​​它在 w &lt; 19 周围添加括号:(w &lt; 19) 是的,11644473600s 可以替代 sys_days1970_y/jan/1 - sys_days1601_y/jan/1 让我们continue this discussion in chat。【参考方案5】:

除法和加法的解决方案在夏令时无法正常工作。

这是一个有效的 sn-p,但它适用于 windows。

time_t FileTime_to_POSIX(FILETIME ft)

    FILETIME localFileTime;
    FileTimeToLocalFileTime(&ft,&localFileTime);
    SYSTEMTIME sysTime;
    FileTimeToSystemTime(&localFileTime,&sysTime);
    struct tm tmtime = 0;
    tmtime.tm_year = sysTime.wYear - 1900;
    tmtime.tm_mon = sysTime.wMonth - 1;
    tmtime.tm_mday = sysTime.wDay;
    tmtime.tm_hour = sysTime.wHour;
    tmtime.tm_min = sysTime.wMinute;
    tmtime.tm_sec = sysTime.wSecond;
    tmtime.tm_wday = 0;
    tmtime.tm_yday = 0;
    tmtime.tm_isdst = -1;
    time_t ret = mktime(&tmtime);
    return ret;

【讨论】:

【参考方案6】:

假设您询问的是FILETIME 结构,然后FileTimeToSystemTime 执行您想要的操作,您可以从它生成的SYSTEMTIME 结构中获取秒数。

【讨论】:

我认为 FileTimeToSystemTime 只能在 Windows 中使用。我正在寻找 Unix/Linux 中的东西。【参考方案7】:

这里基本上是相同的解决方案,除了这个解决方案正确编码来自 Ldap 的负数并在转换前去掉最后 7 位数字。

    public static int LdapValueAsUnixTimestamp(SearchResult searchResult, string fieldName)
    
        var strValue = LdapValue(searchResult, fieldName);
        if (strValue == "0") return 0;
        if (strValue == "9223372036854775807") return -1;

        return (int)(long.Parse(strValue.Substring(0, strValue.Length - 7)) - 11644473600);
    

【讨论】:

【参考方案8】:

如果有人需要在 mysql 中转换它

SELECT timestamp, 
       FROM_UNIXTIME(ROUND((((timestamp) / CAST(10000000 AS UNSIGNED INTEGER))) 
         - CAST(11644473600 AS UNSIGNED INTEGER),0)) 
       AS Converted FROM events  LIMIT 100

【讨论】:

这是对另一个问题的回答。如果您认为它有价值,请ask它(带有此问题的链接)并在那里提供您的答案。【参考方案9】:

这里还有一个纯 C#ian 方法。

(Int32)(DateTime.FromFileTimeUtc(129477880901875000).Subtract(new DateTime(1970, 1, 1))).TotalSeconds;

这是我的即时窗口中两种方法的结果:

(Int32)(DateTime.FromFileTimeUtc(long.Parse(strValue)).Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
1303314490
(int)(long.Parse(strValue.Substring(0, strValue.Length - 7)) - 11644473600)
1303314490
DateTime.FromFileTimeUtc(long.Parse(strValue))
2011-04-20 3:48:10 PM
    Date: 2011-04-20 12:00:00 AM
    Day: 20
    DayOfWeek: Wednesday
    DayOfYear: 110
    Hour: 15
    InternalKind: 4611686018427387904
    InternalTicks: 634389112901875000
    Kind: Utc
    Millisecond: 187
    Minute: 48
    Month: 4
    Second: 10
    Ticks: 634389112901875000
    TimeOfDay: System.TimeSpan
    Year: 2011
    dateData: 5246075131329262904

【讨论】:

以上是关于在 Unix/Linux 中将 Windows 文件时间转换为秒的主要内容,如果未能解决你的问题,请参考以下文章

在 Unix/Linux 中将文件移动到不同目录所需的权限 [关闭]

Windows 机器中的 UNIX/LINUX 本地主机服务器

在 unix (linux/osx) 中创建的符号链接是不是仍然可以在 Windows 中工作?

从事UNIX/LInux服务器编程最方便的代码编译工具------(eclipse for c/c++)(FileZilla)(Secure CRT) 这三种一定要一起使用 之3

漫画 | Unix/Linux 比 Windows 差远了!

干货!一篇文章集合所有Linux基础命令,适合所有菜鸟学习和老手回顾!