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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6161776/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 19:35:01  来源:igfitidea点击:

Convert Windows Filetime to second in Unix/Linux

c++ctime

提问by ARH

I have a trace file that each transaction time represented in Windows filetime format. These time numbers are something like this:

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

  • 128166372003061629
  • 128166372016382155
  • 128166372026382245
  • 128166372003061629
  • 128166372016382155
  • 128166372026382245

Would you please let me know if there are any C/C++ library in Unix/Linux to extract actual time (specially second) from these numbers ? May I write my own extraction function ?

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

回答by Eugene

it's quite simple: the windows epoch starts 1601-01-01T00:00:00Z. It's 11644473600 seconds before the UNIX/Linux epoch (1970-01-01T00:00:00Z). The Windows ticks are in 100 nanoseconds. Thus, a function to get seconds from the UNIX epoch will be as follows:

这很简单:Windows 纪元从 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);
}

回答by ashaw

FILETIME type is is the number 100 ns increments since January 1 1601.

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

To convert this into a unix time_t you can use the following.

要将其转换为 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;
}

you may then use the ctime functions to manipulate it.

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

回答by Howard Hinnant

New answer for old question.

旧问题的新答案。

Using C++11's <chrono>plus this free, open-source library:

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

https://github.com/HowardHinnant/date

https://github.com/HowardHinnant/date

One can very easily convert these timestamps to std::chrono::system_clock::time_point, and also convert these timestamps to human-readable format in the Gregorian calendar:

人们可以很容易地将这些时间戳转换为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';
}

For me this outputs:

对我来说,这个输出:

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

On Windows, you can actually skip the floor, and get that last decimal digit of precision:

在 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

With optimizations on, the sub-expression (sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1})will translate at compile time to days{134774}which will further compile-time-convert to whatever units the full-expression requires (seconds, 100-nanoseconds, whatever). Bottom line: This is both very readable and very efficient.

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

回答by Stan Sieler

(I discovered I can't enter readable code in a comment, so...)

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

Note that Windows can represent times outside the range of POSIX epoch times, and thus a conversion routine should return an "out-of-range" indication as appropriate. The simplest method is:

请注意,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;

回答by Johan K?hler

The solution that divides and adds will not work correctly with daylight savings.

使用夏令时,分割和添加的解决方案将无法正常工作。

Here is a snippet that works, but it is for windows.

这是一个有效的片段,但它适用于 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;
}

回答by Johan K?hler

Assuming you are asking about the FILETIMEStructure, then FileTimeToSystemTimedoes what you want, you can get the seconds from the SYSTEMTIMEstructure it produces.

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

回答by Bluebaron

Here's essentially the same solution except this one encodes negative numbers from Ldap properly and lops off the last 7 digits before conversion.

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

回答by Bluebaron

Also here's a pure C#ian way to do it.

这里还有一个纯粹的 C#ian 方式来做到这一点。

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

Here's the result of both methods in my immediate window:

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

(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

回答by lexxmt

If somebody need convert it in MySQL

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

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