web-dev-qa-db-fra.com

Convertir std :: chrono :: time_point en horodatage unix

Comment puis-je obtenir un std::chrono::duration Depuis une date fixe? J'en ai besoin pour convertir un std::chrono::time_point En horodatage Unix.

Insérez le code dans XXX

auto unix_Epoch_start = XXX;
auto time = std::chrono::system_clock::now();
auto delta = time - unix_epoc_start;
auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(delta).count();

Je sais que time_point A une méthode time_since_Epoch() mais il n'est pas garanti que ce soit la même que l'époque Unix (00:00:00 UTC le 1er janvier 1970).

28
Daniel

Un horodatage Unix est défini comme le nombre de secondes depuis le 1er janvier 1970 UTC, sans compter toutes les secondes. C'est un peu ridicule et il faut se demander à quoi ça sert, donc je conviens que c'est une question idiote.

Quoi qu'il en soit, regardons la documentation de la plate-forme pour time_t Et time().

Linux :

time () renvoie l'heure sous forme de nombre de secondes écoulées depuis l'époque, 1970-01-01 00:00:00 +0000 (UTC).

POSIX.1 définit les secondes depuis l'Époque en utilisant une formule qui se rapproche du nombre de secondes entre un temps spécifié et l'Époque. Cette formule tient compte du fait que toutes les années qui sont divisibles par 4 sont des années bissextiles, mais les années qui sont divisibles par 100 ne sont pas des années bissextiles, sauf si elles sont également divisibles par 400, auquel cas ce sont des années bissextiles. Cette valeur n'est pas la même que le nombre réel de secondes entre l'heure et l'époque, en raison des secondes intercalaires et parce qu'il n'est pas nécessaire de synchroniser les horloges système avec une référence standard. L'intention est que l'interprétation des secondes depuis les valeurs de l'époque soit cohérente; voir POSIX.1-2008 Justification A.4.15 pour plus de justification.

Windows :

La fonction de temps renvoie le nombre de secondes écoulées depuis minuit (00:00:00), le 1er janvier 1970, temps universel coordonné (UTC), selon l'horloge système.

Mac OS X :

Les fonctions ctime (), gmtime () et localtime () prennent toutes comme argument une valeur de temps représentant le temps en secondes depuis l'Epoch (00:00:00 UTC, 1er janvier 1970;

Les fonctions asctime (), ctime (), difftime (), gmtime (), localtime () et mktime () sont conformes à ISO/IEC 9899: 1990 (ISO C90''), and conform to ISO/IEC 9945-1:1996 ( POSIX.1 '') à condition que le le fuseau horaire local ne contient pas de tableau des secondes intercalaires (voir zic (8)).

Une documentation similaire peut être trouvée pour d'autres systèmes, tels que AIX, HP-UX, Solaris, etc.

Ainsi, bien qu'il ne soit pas spécifié dans C++ , il existe un moyen simple et largement portable d'obtenir un horodatage Unix:

auto unix_timestamp = std::chrono::seconds(std::time(NULL));

Et si vous voulez un certain nombre de millisecondes depuis le 1er janvier 1970 UTC (de même sans les compter toutes), vous pouvez le faire:

int unix_timestamp_x_1000 = std::chrono::milliseconds(unix_timestamp).count();

N'oubliez pas que ces valeurs ne sont pas des temps réels, vous ne pouvez donc pas en général utiliser les horodatages Unix en arithmétique. Par exemple, la soustraction d'horodatages Unix ne vous donne pas un décompte précis des secondes entre les heures. Ou si vous avez fait quelque chose comme:

std::chrono::steady_clock::now() - unix_timestamp;

vous n'obtiendrez pas un point de temps correspondant réellement au 1970-01-01 00: 00: 00 + 0000.


Comme Andy Prowl le suggère, vous pourriez faire quelque chose de stupide comme:

// 1 Jan 1970 (no time zone)
std::tm c = { 0, 0, 0, 1, 0, 70, 0, 0, -1};

// treat it as 1 Jan 1970 (your system's time zone) and get the
// number of seconds since your system's Epoch (leap seconds may
// or may not be included)
std::time_t l = std::mktime(&c);

// get a calender time for that time_point in UTC. When interpreted
// as UTC this represents the same calendar date and time as the
// original, but if we change the timezone to the system TZ then it
// represents a time offset from the original calendar time by as
// much as UTC differs from the local timezone.
std::tm m = *std::gmtime(&l);

// Treat the new calendar time as offset time in the local TZ. Get
// the number of seconds since the system Epoch (again, leap seconds
// may or may not be counted).
std::time_t n = std::mktime(&m);

l -= (n-l); // subtract the difference

l devrait maintenant représenter le (mauvais) nombre de secondes depuis le 1er janvier 1970 UTC. Tant qu'il n'y a pas de secondes intercalaires entre l'Époque du système et le 1er janvier 1970 (fuseau horaire du système), ou dans un délai égal dans l'autre sens par rapport à l'Époque du système, toutes les secondes intercalaires comptées doivent s'annuler et l sera erroné de la même manière que les horodatages Unix sont erronés.


Une autre option consiste à utiliser une bibliothèque de date décente telle que chrono::date De Howard Hinnant . (Howard Hinnant était l'un des gars qui a travaillé sur la bibliothèque C++ 11 <chrono>.)

auto now = system_clock::now();
sys_days today = time_point_cast<days>(now);
system_clock::time_point this_morning = today;

sys_days unix_Epoch = day(1)/jan/1970;
days days_since_Epoch = today - unix_Epoch;

auto s = now - this_morning;

auto tz_offset = hours(0);
int unix_timestamp = (days_since_Epoch + s + tz_offset) / seconds(1);

Si vous voulez gérer les secondes intercalaires, Howard Hinnant fournit également ne bibliothèque qui inclut des fonctionnalités pour les gérer ainsi que pour analyser les bases de données de fuseaux horaires comme source pour les données des secondes intercalaires.

32
bames53

Pour faire court, voici la fonction que j'utilise pour obtenir l'horodatage Unix (les secondes comptent depuis le 1er janvier 1970 UTC):

static uint64_t getUnixTimeStamp(const std::time_t* t = nullptr)
{
    //if specific time is not passed then get current time
    std::time_t st = t == nullptr ? std::time(nullptr) : *t;
    auto secs = static_cast<std::chrono::seconds>(st).count();
    return static_cast<uint64_t>(secs);
}

L'avantage de cette fonction est que la valeur par défaut du paramètre vous donne juste l'heure actuelle. Cependant, si vous souhaitez convertir une heure spécifique en horodatage Unix, vous pouvez également le faire.

7
Shital Shah

qu'en est-il de cette implémentation C++ 11

auto microsecondsUTC = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_Epoch()).count();
4
siamoss

Vous pouvez utiliser mktime() pour convertir la date souhaitée encodée dans une structure tm en une valeur heure localetime_t.

Si vous avez besoin d'une heure UTC, utilisez gmttime() pour convertir cette valeur time_t En une structure UTC tm, et déterminez à partir de la sortie que vous obtenez tm la structure produit l'UTC time_t souhaitée lorsqu'elle est entrée en mktime().

Un peu élaboré, mais j'espère que cela fonctionnera ou du moins donnera un indice.

2
Andy Prowl