web-dev-qa-db-fra.com

Convertir Windows Filetime en seconde sous Unix / Linux

J'ai un fichier de trace que chaque temps de transaction représenté au format filetime Windows. Ces nombres de temps sont quelque chose comme ceci:

  • 128166372003061629
  • 128166372016382155
  • 128166372026382245

Pourriez-vous s'il vous plaît me faire savoir s'il existe une bibliothèque C/C++ dans Unix/Linux pour extraire l'heure réelle (spécialement la seconde) de ces nombres? Puis-je écrire ma propre fonction d'extraction?

34
ARH

c'est assez simple: la fenêtre Epoch démarre 1601-01-01T00: 00: 00Z. C'est 11644473600 secondes avant l'époque UNIX/Linux (1970-01-01T00: 00: 00Z). Les ticks de Windows sont en 100 nanosecondes. Ainsi, une fonction pour obtenir des secondes de l'époque UNIX sera la suivante:

#define WINDOWS_TICK 10000000
#define SEC_TO_UNIX_Epoch 11644473600LL

unsigned WindowsTickToUnixSeconds(long long windowsTicks)
{
     return (unsigned)(windowsTicks / WINDOWS_TICK - SEC_TO_UNIX_Epoch);
}
59
Eugene

Le type FILETIME est le nombre incréments de 100 ns depuis le 1er janvier 1601.

Pour convertir ceci en un time_t unix, vous pouvez utiliser ce qui suit.

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

vous pouvez ensuite utiliser les fonctions ctime pour le manipuler.

11
ashaw

(J'ai découvert que je ne peux pas entrer de code lisible dans un commentaire, alors ...)

Notez que Windows peut représenter des temps en dehors de la plage de temps POSIX Epoch, et donc une routine de conversion doit retourner une indication "hors plage" selon le cas. La méthode la plus simple est:

   ... (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;
6
Stan Sieler

Nouvelle réponse à une ancienne question.

Utilisation de <chrono> De C++ 11 et de cette bibliothèque open source gratuite:

https://github.com/HowardHinnant/date

On peut très facilement convertir ces horodatages en std::chrono::system_clock::time_point, Et également convertir ces horodatages au format lisible par l'homme dans le calendrier grégorien:

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

Pour moi, cela produit:

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

Sous Windows, vous pouvez réellement ignorer le floor et obtenir ce dernier chiffre décimal de précision:

    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

Lorsque les optimisations sont activées, la sous-expression (sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1}) Se traduira au moment de la compilation en days{134774}, Ce qui convertira davantage le temps de compilation en toutes les unités requises par l'expression complète (secondes, 100 nanosecondes, quelle que soit ). Conclusion: c'est à la fois très lisible et très efficace.

6
Howard Hinnant

La solution qui divise et ajoute ne fonctionnera pas correctement avec l'heure d'été.

Voici un extrait qui fonctionne, mais c'est pour 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;
}
1
Johan Köhler

Voici essentiellement la même solution, sauf que celle-ci code correctement les nombres négatifs de Ldap et coupe les 7 derniers chiffres avant la 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);
    }
0
Bluebaron

En supposant que vous posez des questions sur la structure FILETIME , alors FileTimeToSystemTime fait ce que vous voulez, vous pouvez obtenir les secondes du HEURE SYSTÈME structure qu'il produit.

0
user2100815