Convertir std:: chrono:: point de temps en timestamp unix
Comment puis-je obtenir un std::chrono::duration
depuis une date fixe? J'en ai besoin pour convertir un std::chrono::time_point
à un timestamp 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 time_point
a une méthode time_since_epoch()
mais il n'est pas garanti que ce soit la même chose que l'époque unix (00:00:00 UTC au 1er janvier 1970).
3 réponses
un horodatage unix est défini comme le nombre de secondes depuis le 1er janvier 1970 UTC, sauf pour ne pas compter toutes les secondes. C'est un peu ridicule et il faut se demander à quoi cela sert, alors je suis d'accord pour dire qu'il s'agit d'une question idiote.
de toute façon, regardons un peu de documentation de la plate-forme pour time_t
et time()
.
time() retourne le temps comme le nombre de secondes depuis l'Epoch, 1970-01-01 00:00: 00 +0000 (UTC).
POSIX.1 définit 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 divisibles par 4 sont bissextiles les années, mais les années divisibles par 100 ne sont pas des années bissextiles, sauf s'ils sont aussi divisibles par 400, dans ce cas, ils sont des années bissextiles. Cette valeur n'est pas la même que le nombre réel de secondes entre le temps et L'époque, en raison des secondes bissextiles et parce que les horloges système ne sont pas tenus d'être synchronisés à une référence standard. L'intention est que l'interprétation des secondes depuis les valeurs D'époque soit cohérente; voir POSIX.1-2008 Justification A. 4.15 for further rationale.
la fonction time renvoie le nombre de secondes écoulées depuis minuit (00:00:00), le 1er janvier 1970, temps universel coordonné (UTC)), selon l'horloge du système.
les fonctions ctime (), gmtime (), et localtime () prennent toutes comme argument une valeur de temps représentant le temps en secondes depuis l'époque (00:00: 00 UTC, 1er janvier 1970;
Le asctime(), ctime(), difftime(), gmtime(), localtime () et mktime() fonctions conformes à la norme ISO / IEC 9899: 1990 (
ISO C90''), and conform to ISO/IEC 9945-1:1996 (
POSIX.1") à condition que le fuseau horaire local sélectionné ne contient pas de saut-deuxième tableau (voir la zic(8)).
une documentation similaire peut être trouvée pour d'autres systèmes, tels que AIX, HP-UX, Solaris, etc.
ainsi bien que non spécifié dans c++ il existe un moyen facile et largement portable d'obtenir un timestamp 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 la même façon, ne pas les compter toutes) alors vous pouvez faire ceci:
int unix_timestamp_x_1000 = std::chrono::milliseconds(unix_timestamp).count();
Juste rappelez-vous que ces valeurs ne sont pas des temps réels, de sorte que vous ne pouvez pas en général utiliser unix horodateurs en arithmétique. Par exemple, la soustraction des horodateurs unix ne vous donne pas un compte exact des secondes entre les temps. Ou si vous avez quelque chose comme:
std::chrono::steady_clock::now() - unix_timestamp;
vous n'obtiendriez pas un point de temps correspondant en fait à 1970-01-01 00:00: 00+0000.
comme le suggère Andy Prowl, 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ésente le nombre (erroné) de secondes depuis le 1er janvier 1970 UTC. Tant qu'il n'y a pas de seconde bissextile entre l'époque du système et le 1er janvier 1970 (fuseau horaire du système), ou dans une quantité égale de temps dans l'autre direction de l'époque du système, alors toute seconde bissextile comptée devrait annuler et l
sera erroné de la même façon que les horodateurs unix sont erronés.
une autre option est d'utiliser une bibliothèque de date décente telle que Howard Hinnant de l' chrono::date
. (Howard Hinnant était l'un des gars qui a travaillé sur le C++11 <chrono>
bibliothèque.)
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 bissextiles, Howard Hinnant fournit aussi bibliothèque Cela inclut les installations pour les manipuler ainsi que pour analyser les bases de données de fuseaux horaires comme source pour les données de seconde bissextile.
pour faire court, voici la fonction que j'utilise pour obtenir le timestamp Unix (nombre de secondes 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 ne donne que l'heure courante. Cependant, si vous voulez convertir un temps spécifique à unix timestamp, vous pouvez le faire aussi.
Vous pouvez utiliser mktime()
pour convertir la date désirée encodée dans un tm
structure en un -time_t
valeur.
si vous avez besoin D'un temps UTC, utilisez gmttime()
convertir time_t
valeur en UTC tm
structure, et de comprendre à partir de la sortie qui tm
la structure donne L'UTC désirée time_t
lorsqu'elle est donnée en entrée à mktime()
.
Un peu élaboré, mais j'espère qu'il va travailler ou au moins fournir un indice.