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

nuypyhwy  于 2023-05-16  发布在  Unix
关注(0)|答案(9)|浏览(152)

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

  • 128166372003061629
  • 128166372016382155
  • 128166372026382245

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

7nbnzgx9

7nbnzgx91#

很简单:窗口时期开始于1601-01- 01 T00:00:00 Z。它比UNIX/Linux纪元(1970-01- 01 T00:00:00 Z)早11644473600秒。Windows刻度以100纳秒为单位。因此,从UNIX epoch获取秒的函数将如下:

#define WINDOWS_TICK 10000000
#define SEC_TO_UNIX_EPOCH 11644473600LL

unsigned WindowsTickToUnixSeconds(long long windowsTicks)
{
     return (unsigned)(windowsTicks / WINDOWS_TICK - SEC_TO_UNIX_EPOCH);
}
w9apscun

w9apscun2#

FILETIME类型是自1601年1月1日以来以100ns递增的数字。
要将其转换为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函数来操作它。

nzkunb0c

nzkunb0c3#

(我发现我不能在注解中输入可读代码,所以……)
请注意,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;
bq8i3lrv

bq8i3lrv4#

老问题的新答案
使用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';
}

对我来说,这输出:

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_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

在优化打开的情况下,子表达式(sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1})将在编译时转换为days{134774},后者将进一步在编译时转换为完整表达式所需的任何单位(秒、100纳秒等)。底线是:这是非常可读和非常有效的。

v8wbuo2f

v8wbuo2f5#

除法和加法的解决方案将无法在夏令时正常工作。
下面是一个可以工作的代码片段,但它是针对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;
}
iswrvxsc

iswrvxsc6#

假设您询问的是FILETIME结构,那么FileTimeToSystemTime会按照您的要求执行操作,您可以从它生成的SYSTEMTIME结构中获取秒数。

91zkwejq

91zkwejq7#

这里基本上是相同的解决方案,除了这个正确地从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);
    }
uurity8g

uurity8g8#

如果有人需要将其转换为MySQL

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

2jcobegt9#

这里也有一个纯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

相关问题