Convert Windows Filetime to second in Unix/Linux
Solution 1
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:
#define WINDOWS_TICK 10000000
#define SEC_TO_UNIX_EPOCH 11644473600LL
unsigned WindowsTickToUnixSeconds(long long windowsTicks)
{
return (unsigned)(windowsTicks / WINDOWS_TICK - SEC_TO_UNIX_EPOCH);
}
Solution 2
FILETIME type is is the number 100 ns increments since January 1 1601.
To convert this into a unix time_t you can use the following.
#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.
Solution 3
New answer for old question.
Using C++11's <chrono>
plus this free, open-source library:
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:
#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:
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.
Solution 4
(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:
... (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;
Solution 5
The solution that divides and adds will not work correctly with daylight savings.
Here is a snippet that works, but it is for 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;
}
ARH
Updated on May 22, 2020Comments
-
ARH about 4 years
I have a trace file that each transaction time represented in Windows filetime format. These time numbers are something like this:
- 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 ?
-
Dietrich Epp about 13 yearsNote that the 11644473600 does not count leap seconds.
-
Dietrich Epp about 13 yearsNote that the intervals here do not count leap seconds.
-
faridSam almost 12 yearsBut see also Does the windows FILETIME structure include leap seconds? (@DietrichEpp)
-
Stan Sieler over 11 yearsNote 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: ` long long secs; time_t t; secs = (windowsTicks / WINDOWS_TICK - SEC_TO_UNIX_EPOCH); t = (time_t) secs; if (secs != (long long) t) return (time_t) -1; return t; `
-
guilleamodeo about 9 years@Dietrich epp. Leap seconds were introduced in 1972. So there is none between 1601 and 1970 and thus irrelevant in this conversion.
-
guilleamodeo about 9 years@Dietrich epp. Leap seconds were introduced in 1972. So there is none between 1601 and 1970 and thus irrelevant in this conversion.
-
Toby Speight about 8 yearsThis is an answer to a different question. If you believe it has value, please ask it (with a link to this question) and provide your answer there.
-
Bluebaron about 8 yearsI have to do the same thing but what I found is that you're probably extracting these numbers as strings to being with. If that's the case, you can just lop off the last 7 digits.
-
mR.aTA almost 8 years@Eugene What about convert nanoseocnd to windows ticks?
-
Eugene almost 8 years@mR.aTA I'm sorry but I did not understand the questions. What is the start point for nanoseconds counting? Anyway, using ticks you cannot measure nanoseconds exactly, since 1 tick = 100 ns
-
BmyGuest over 3 yearsQuestion for the date.h library, that is literally just copying the data.h file from your GIT repository and including it, correct? I'm asking, because if I do so, I get a compile error in data.h as
date.h(3832): error C2059: syntax error: '}'
-
BmyGuest over 3 yearsIf I would not use the date.h, then the only difference to your code above would be to use
seconds{ 11644473600LL }
instead of(sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1})
, correct? -
Howard Hinnant over 3 yearsThanks for the report. It looks like VS is misinterpreting a
<
as an open template token instead of a less-than token. I've just pushed a fix. Could you try again? The fixed line is 3689 which adds parentheses aroundw < 19
:(w < 19)
. -
Howard Hinnant over 3 yearsYes,
11644473600s
is an acceptable replacement forsys_days{1970_y/jan/1} - sys_days{1601_y/jan/1}
. -
BmyGuest over 3 yearsLet us continue this discussion in chat.