Конвертировать время файла Windows в секунду в Unix / Linux - PullRequest
31 голосов
/ 28 мая 2011

У меня есть файл трассировки, который время каждой транзакции представлено в формате времени файла Windows. Эти временные числа примерно такие:

  • 128166372003061629
  • 128166372016382155
  • 128166372026382245

Не могли бы вы сообщить мне, есть ли какая-либо библиотека C / C ++ в Unix / Linux для извлечения текущего времени (особенно секунды) из этих чисел? Могу ли я написать свою собственную функцию извлечения?

Ответы [ 9 ]

54 голосов
/ 28 мая 2011

все довольно просто: эпоха windows начинается 1601-01-01T00: 00: 00Z. Это 11644473600 секунд до эпохи UNIX / Linux (1970-01-01T00: 00: 00Z). Тики 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);
}
9 голосов
/ 28 мая 2011

FILETIME тип - это число с шагом 100 нс с 1 января 1601 года.

Чтобы преобразовать это в 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 для управления им.

6 голосов
/ 11 марта 2016

Новый ответ на старый вопрос.

Использование C ++ 11's <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 наносекунд и т. д.).Итог: это очень читабельно и очень эффективно.

6 голосов
/ 02 марта 2013

(я обнаружил, что не могу ввести читаемый код в комментарии, поэтому ...)

Обратите внимание, что 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;
1 голос
/ 17 октября 2014

Решение, которое разделяет и добавляет, не будет работать правильно с переходом на летнее время.

Вот фрагмент кода, который работает, но это для 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;
}
0 голосов
/ 11 марта 2016

Также вот простой способ сделать это на 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
0 голосов
/ 11 марта 2016

Это, по сути, то же самое решение, за исключением того, что оно правильно кодирует отрицательные числа из 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);
    }
0 голосов
/ 09 марта 2016

Если кому-то нужно конвертировать его в MySQL

SELECT timestamp, 
       FROM_UNIXTIME(ROUND((((timestamp) / CAST(10000000 AS UNSIGNED INTEGER))) 
         - CAST(11644473600 AS UNSIGNED INTEGER),0)) 
       AS Converted FROM events  LIMIT 100
0 голосов
/ 28 мая 2011

Если вы спрашиваете о структуре FILETIME , то FileTimeToSystemTime делает то, что вам нужно, вы можете получить секунды из структуры SYSTEMTIME , которую она производит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...