在Unix/Linux中将Windows Filetime转换为第二

ARH*_*ARH 32 c c++ time

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

  • 128166372003061629
  • 128166372016382155
  • 128166372026382245

如果Unix/Linux中有任何C/C++库从这些数字中提取实际时间(特别是第二个),请告诉我吗?我可以编写自己的提取功能吗?

Eug*_*ene 55

这很简单: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);
}
Run Code Online (Sandbox Code Playgroud)

  • @Dietrich epp.闰秒是在1972年引入的.因此1601和1970之间没有闰秒,因此在这种转换中无关紧要. (18认同)
  • 请注意,11644473600不计算闰秒. (3认同)

ash*_*haw 11

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

然后,您可以使用ctime函数来操作它.

  • @Dietrich epp.闰秒是在1972年引入的.因此1601和1970之间没有闰秒,因此在这种转换中无关紧要. (6认同)

Sta*_*ler 6

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

请注意,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;
Run Code Online (Sandbox Code Playgroud)


How*_*ant 6

旧问题的新答案.

使用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_point{floor<system_clock::duration>(wfs{t} -
                        (sys_days{1970_y/jan/1} - sys_days{1601_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';
}
Run Code Online (Sandbox Code Playgroud)

对我来说这个输出:

2007-02-22 17:00:00.306162
2007-02-22 17:00:01.638215
2007-02-22 17:00:02.638224
Run Code Online (Sandbox Code Playgroud)

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

    return system_clock::time_point{wfs{t} -
                        (sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1})};

2007-02-22 17:00:00.3061629
2007-02-22 17:00:01.6382155
2007-02-22 17:00:02.6382245
Run Code Online (Sandbox Code Playgroud)

通过优化,子表达式(sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1})将在编译时days{134774}转换为进一步编译时转换为full-expression所需的任何单位(秒,100纳秒,无论如何).底线:这是非常可读和非常有效的.