在Unix / Linux中将Windows Filetime转换为第二个
我有一个跟踪文件,每个交易时间以Windows文件时间格式表示。 这些时间的数字是这样的:
- 128166372003061629
- 128166372016382155
- 128166372026382245
如果在Unix / Linux中有任何C / C ++库来从这些数字中提取实际时间(特别是第二个),请告诉我一下吗? 我可以写我自己的提取function吗?
这很简单:窗口时代开始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); }
FILETIMEtypes是自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函数来操纵它。
(我发现我不能在评论中input可读的代码,所以…)
请注意,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;
老问题的新答案。
使用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
通过优化,子expression式(sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1})
将在编译时翻译为days{134774}
,这将进一步编译时转换为任何单元满expression需要(秒,100纳秒,无论)。 底线:这是非常可读和非常有效的。
假设你问的是FILETIME结构,那么FileTimeToSystemTime就是你想要的,你可以从它产生的SYSTEMTIME结构中获得秒数。
夏时制的解决scheme将无法正常工作。
这是一个可以工作的代码片段,但它是用于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; }
这里基本上是相同的解决scheme,除了这个从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); }
这里还有一个纯C#的方法来做到这一点。
(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
如果有人需要在MySQL中进行转换
SELECT timestamp, FROM_UNIXTIME(ROUND((((timestamp) / CAST(10000000 AS UNSIGNED INTEGER))) - CAST(11644473600 AS UNSIGNED INTEGER),0)) AS Converted FROM events LIMIT 100