web-dev-qa-db-fra.com

Extraire année / mois / jour etc. de std :: chrono :: time_point en C ++

Comment puis-je extraire le année, mois, jour, heure, minute, seconde et milliseconde d'un std::chrono::time_point objet?

Je n'ai vu que des exemples sur la façon d'extraire le montant total de, par ex. secondes à partir d'un duration.

42
bytecode77

Vous pouvez uniquement extraire ces informations d'un system_clock::time_point. Il s'agit de la seule horloge fournie par le système qui a une relation avec le calendrier civil. Voici comment obtenir le point de temps actuel en utilisant cette horloge:

 system_clock::time_point now = system_clock::now();

Vous pouvez ensuite le convertir en time_t avec:

time_t tt = system_clock::to_time_t(now);

En utilisant la bibliothèque C, vous pouvez ensuite convertir un time_t en tm, mais vous devez choisir si vous souhaitez que cette conversion se produise dans le fuseau horaire UTC ou votre fuseau horaire local:

tm utc_tm = *gmtime(&tt);
tm local_tm = *localtime(&tt);

Ensuite, vous pouvez imprimer les composants du tm, par exemple:

std::cout << local_tm.tm_year + 1900 << '\n';
std::cout << local_tm.tm_mon + 1 << '\n';
std::cout << local_tm.tm_mday << '\n';

De plus

Si vous le souhaitez, vous pouvez profiter de ces informations non garanties:

Chaque implémentation de system_clock Dont je suis conscient est basé sur nix time . C'est à dire. le nombre de secondes depuis le Nouvel An 1970 UTC, en négligeant les secondes intercalaires. Et la précision de ce compte est généralement plus fine que les secondes. Voici un programme complet qui extrait toutes ces informations:

#include <chrono>
#include <ctime>
#include <iostream>

int
main()
{
    using namespace std;
    using namespace std::chrono;
    typedef duration<int, ratio_multiply<hours::period, ratio<24> >::type> days;
    system_clock::time_point now = system_clock::now();
    system_clock::duration tp = now.time_since_Epoch();
    days d = duration_cast<days>(tp);
    tp -= d;
    hours h = duration_cast<hours>(tp);
    tp -= h;
    minutes m = duration_cast<minutes>(tp);
    tp -= m;
    seconds s = duration_cast<seconds>(tp);
    tp -= s;
    std::cout << d.count() << "d " << h.count() << ':'
              << m.count() << ':' << s.count();
    std::cout << " " << tp.count() << "["
              << system_clock::duration::period::num << '/'
              << system_clock::duration::period::den << "]\n";

    time_t tt = system_clock::to_time_t(now);
    tm utc_tm = *gmtime(&tt);
    tm local_tm = *localtime(&tt);
    std::cout << utc_tm.tm_year + 1900 << '-';
    std::cout << utc_tm.tm_mon + 1 << '-';
    std::cout << utc_tm.tm_mday << ' ';
    std::cout << utc_tm.tm_hour << ':';
    std::cout << utc_tm.tm_min << ':';
    std::cout << utc_tm.tm_sec << '\n';
}

Il est pratique de créer un duration personnalisé pour modéliser les jours:

typedef duration<int, ratio_multiply<hours::period, ratio<24> >::type> days;

Maintenant, vous pouvez obtenir le temps depuis l'époque, avec une précision aussi fine que possible, avec:

system_clock::duration tp = now.time_since_Epoch();

Ensuite, tronquez-le en jours et soustrayez-le.

Ensuite, tronquez-le en heures et soustrayez-le.

Continuez jusqu'à ce que vous ayez soustrait les secondes.

Ce qui vous reste est la fraction de seconde avec les unités de system_clock::duration. Imprimez donc cette valeur d'exécution et les unités de temps de compilation de cette valeur, comme indiqué.

Pour moi, ce programme imprime:

15806d 20:31:14 598155[1/1000000]
2013-4-11 20:31:14

Ma sortie indique le system_clock::duration la précision est en microsecondes. Si vous le souhaitez, cela peut être tronqué en millisecondes avec:

milliseconds ms = duration_cast<milliseconds>(tp);

Mise à jour

Cette bibliothèque C++ 11/14 uniquement en-tête encapsule le travail ci-dessus, réduisant le travail du client à:

#include "date.h"
#include <iostream>

int
main()
{
    // Reduce verbosity but let you know what is in what namespace
    namespace C = std::chrono;
    namespace D = date;
    namespace S = std;

    auto tp = C::system_clock::now(); // tp is a C::system_clock::time_point
    {
        // Need to reach into namespace date for this streaming operator
        using namespace date;
        S::cout << tp << '\n';
    }
    auto dp = D::floor<D::days>(tp);  // dp is a sys_days, which is a
                                      // type alias for a C::time_point
    auto ymd = D::year_month_day{dp};
    auto time = D::make_time(C::duration_cast<C::milliseconds>(tp-dp));
    S::cout << "year        = " << ymd.year() << '\n';
    S::cout << "month       = " << ymd.month() << '\n';
    S::cout << "day         = " << ymd.day() << '\n';
    S::cout << "hour        = " << time.hours().count() << "h\n";
    S::cout << "minute      = " << time.minutes().count() << "min\n";
    S::cout << "second      = " << time.seconds().count() << "s\n";
    S::cout << "millisecond = " << time.subseconds().count() << "ms\n";
}

Ce qui vient de sortir pour moi:

2015-07-10 20:10:36.023017
year        = 2015
month       = Jul
day         = 10
hour        = 20h
minute      = 10min
second      = 36s
millisecond = 23ms

Une autre mise à jour

Cette bibliothèque est devenue une proposition de normes C++ et est maintenant dans le projet de travail C++ 20. La syntaxe pour extraire ces champs d'un system_clock::time_point en C++ 20 sera:

#include <chrono>

int
main()
{
    using namespace std::chrono;
    auto tp = system_clock::now();
    auto dp = floor<days>(tp);
    year_month_day ymd{dp};
    hh_mm_ss time{floor<milliseconds>(tp-dp)};
    auto y = ymd.year();
    auto m = ymd.month();
    auto d = ymd.day();
    auto h = time.hours();
    auto M = time.minutes();
    auto s = time.seconds();
    auto ms = time.subseconds();
}

Ce qui précède suppose que vous voulez ces champs en UTC. Si vous les préférez dans un autre fuseau horaire, cela sera également possible. Par exemple, voici comment procéder dans le fuseau horaire local actuel de votre ordinateur:

#include <chrono>

int
main()
{
    using namespace std::chrono;
    auto tp = zoned_time{current_zone(), system_clock::now()}.get_local_time();
    auto dp = floor<days>(tp);
    year_month_day ymd{dp};
    hh_mm_ss time{floor<milliseconds>(tp-dp)};
    auto y = ymd.year();
    auto m = ymd.month();
    auto d = ymd.day();
    auto h = time.hours();
    auto M = time.minutes();
    auto s = time.seconds();
    auto ms = time.subseconds();
}

La seule différence ci-dessus est la construction de tp qui a maintenant le type local_time par opposition à sys_time dans l'exemple UTC. Alternativement, on aurait pu choisir un fuseau horaire arbitraire avec ce petit changement:

auto tp = zoned_time{"Europe/London", system_clock::now()}.get_local_time();
64
Howard Hinnant