42

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 ?

ARH
  • 1,355
  • 3
  • 18
  • 32

9 Answers9

74

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);
}
Eugene
  • 2,858
  • 1
  • 26
  • 25
  • 3
    Note that the 11644473600 does not count leap seconds. – Dietrich Epp May 28 '11 at 18:57
  • 1
    But see also [Does the windows FILETIME structure include leap seconds?](http://stackoverflow.com/questions/130573) (@DietrichEpp) – Ian Goldby Jul 12 '12 at 12:47
  • 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: ` 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; ` – Stan Sieler Mar 02 '13 at 01:11
  • 30
    @Dietrich epp. Leap seconds were introduced in 1972. So there is none between 1601 and 1970 and thus irrelevant in this conversion. – guilleamodeo Apr 07 '15 at 15:16
  • I 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. – Bluebaron Mar 10 '16 at 21:11
  • @Eugene What about convert nanoseocnd to windows ticks? – mR.aTA Jun 10 '16 at 14:20
  • @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 – Eugene Jun 15 '16 at 19:36
14

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.

alternative
  • 12,703
  • 5
  • 41
  • 41
ashaw
  • 187
  • 8
  • 1
    Note that the intervals here do not count leap seconds. – Dietrich Epp May 28 '11 at 18:58
  • 12
    @Dietrich epp. Leap seconds were introduced in 1972. So there is none between 1601 and 1970 and thus irrelevant in this conversion. – guilleamodeo Apr 07 '15 at 15:17
  • @ashaw, to use `convertWindowsTimeToUnixTime` from your answer, do we cast the `FILETIME` to a `long long int` in order to call the function? – Shane Bishop Jan 11 '23 at 17:01
  • @ShaneBishop You can see [here](https://stackoverflow.com/questions/1566645/filetime-to-int64) for a discussion of this. Basically you just or the high and low parts into a new int64 (which is long long int on x86.) – ashaw Jan 12 '23 at 03:42
8

(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;
Stan Sieler
  • 729
  • 7
  • 16
8

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.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • 1
    Question 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 Oct 02 '20 at 16:26
  • 1
    If 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? – BmyGuest Oct 02 '20 at 16:50
  • 1
    Thanks 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 around `w < 19`: `(w < 19)`. – Howard Hinnant Oct 02 '20 at 16:55
  • Yes, `11644473600s` is an acceptable replacement for `sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1}`. – Howard Hinnant Oct 02 '20 at 16:58
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/222417/discussion-between-bmyguest-and-howard-hinnant). – BmyGuest Oct 02 '20 at 17:09
2

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;
}
  • Are you sure your solution makes a difference? Do you have an example input and output for which it is correct, but other answers are oncorrect? – pts Mar 15 '23 at 21:49
0

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

    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);
    }
Bluebaron
  • 2,289
  • 2
  • 27
  • 37
0

Assuming you are asking about the FILETIME Structure, then FileTimeToSystemTime does what you want, you can get the seconds from the SYSTEMTIME structure it produces.

  • I think `FileTimeToSystemTime` can used in Windows only. I am looking for something in Unix/Linux. – ARH May 30 '11 at 10:25
-1

If somebody need convert it in MySQL

SELECT timestamp, 
       FROM_UNIXTIME(ROUND((((timestamp) / CAST(10000000 AS UNSIGNED INTEGER))) 
         - CAST(11644473600 AS UNSIGNED INTEGER),0)) 
       AS Converted FROM events  LIMIT 100
rioki
  • 5,988
  • 5
  • 32
  • 55
lexxmt
  • 11
  • 1
    This is an answer to a different question. If you believe it has value, please [ask](/questions/ask) it (with a link to this question) and provide your answer there. – Toby Speight Mar 09 '16 at 12:01
-1

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

(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
Bluebaron
  • 2,289
  • 2
  • 27
  • 37