Converta o Windows Filetime em segundo no Unix / Linux

Eu tenho um arquivo de rastreamento que cada tempo de transação representado no formato de filetime do Windows. Esses números de tempo são algo assim:

  • 128166372003061629
  • 128166372016382155
  • 128166372026382245

Você poderia, por favor, me avisar se houver alguma biblioteca C / C ++ no Unix / Linux para extrair o tempo real (especialmente o segundo) desses números? Posso escrever minha própria function de extração?

é bem simples: a época do Windows começa em 1601-01-01T00: 00: 00Z. São 11644473600 segundos antes da época do UNIX / Linux (1970-01-01T00: 00: 00Z). Os tiques do Windows estão em 100 nanossegundos. Assim, uma function para obter segundos da época do UNIX será a seguinte:

#define WINDOWS_TICK 10000000 #define SEC_TO_UNIX_EPOCH 11644473600LL unsigned WindowsTickToUnixSeconds(long long windowsTicks) { return (unsigned)(windowsTicks / WINDOWS_TICK - SEC_TO_UNIX_EPOCH); } 

O tipo FILETIME é o número de incrementos de 100 ns desde 1º de janeiro de 1601.

Para converter isso em um unix time_t, você pode usar o seguinte.

 #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; } 

você pode então usar as funções do ctime para manipulá-lo.

(Eu descobri que não posso inserir código legível em um comentário, então …)

Observe que o Windows pode representar tempos fora do intervalo de tempos POSIX épocas e, portanto, uma rotina de conversão deve retornar uma indicação “fora do intervalo” conforme apropriado. O método mais simples é:

  ... (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; 

Nova resposta para pergunta antiga.

Usando C + + 11’s mais esta biblioteca livre e de código aberto:

https://github.com/HowardHinnant/date

É fácil converter esses carimbos de data / hora em std::chrono::system_clock::time_point e também converter esses timestamps em formato legível no calendar gregoriano:

 #include "date.h" #include  std::chrono::system_clock::time_point from_windows_filetime(long long t) { using namespace std::chrono; using namespace date; using wfs = duration>; return system_clock::time_point{floor(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'; } 

Para mim, isso gera:

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

No Windows, você pode pular o floor e obter o último dígito decimal de precisão:

  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 

Com as otimizações (sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1}) , a sub-expressão (sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1}) irá traduzir em tempo de compilation para days{134774} que irão converter em tempo de compilation para qualquer unidade -expressão requer (segundos, 100 nanossegundos, seja o que for). Conclusão: isso é muito legível e muito eficiente.

Supondo que você esteja perguntando sobre a Estrutura FILETIME , FileTimeToSystemTime faz o que você quer, você pode obter os segundos da estrutura SYSTEMTIME que ela produz.

A solução que divide e adiciona não funcionará corretamente com o horário de verão.

Aqui está um trecho que funciona, mas é para o 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; } 

Aqui está essencialmente a mesma solução, exceto que esta codifica números negativos do Ldap corretamente e elimina os últimos 7 dígitos antes da conversão.

  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); } 

Também aqui está uma maneira pura de fazer isso.

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

Aqui está o resultado de ambos os methods na minha janela imediata:

 (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 

Se alguém precisar convertê-lo no MySQL

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