38 votes

Alternative C++11 à localtime_r

Le C++ définit les fonctions de formatage du temps en termes de strftime ce qui nécessite un struct tm l'enregistrement du "temps décomposé". Cependant, les langages C et C++03 ne fournissent pas de moyen sûr pour obtenir un tel enregistrement ; il n'y a qu'un seul maître. struct tm pour l'ensemble du programme.

En C++03, cela était plus ou moins acceptable, car le langage ne prenait pas en charge le multithreading ; il ne faisait que supporter les plates-formes supportant le multithreading, qui fournissaient alors des facilités comme POSIX localtime_r .

C++11 définit également de nouveaux utilitaires temporels, qui s'interfacent avec l'interface non brisée de l'outil de gestion du temps. time_t type, qui est ce qui serait utilisé pour réinitialiser le global struct tm . Mais l'obtention d'un time_t n'est pas le problème.

Est-ce que j'ai raté quelque chose ou est-ce que cette tâche nécessite toujours de s'appuyer sur POSIX ?

EDIT : Voici un code de contournement. Il permet de maintenir la compatibilité avec les environnements multithreads qui offrent ::localtime_r et les environnements monofilaires qui ne fournissent que std::localtime . Il peut facilement être adapté pour vérifier d'autres fonctions, telles que posix::localtime_r o ::localtime_s ou ce que vous voulez.

namespace query {
    char localtime_r( ... );

    struct has_localtime_r
        { enum { value = sizeof localtime_r( std::declval< std::time_t * >(), std::declval< std::tm * >() )
                        == sizeof( std::tm * ) }; };

    template< bool available > struct safest_localtime {
        static std::tm *call( std::time_t const *t, std::tm *r )
            { return localtime_r( t, r ); }
    };

    template<> struct safest_localtime< false > {
        static std::tm *call( std::time_t const *t, std::tm *r )
            { return std::localtime( t ); }
    };
}
std::tm *localtime( std::time_t const *t, std::tm *r )
    { return query::safest_localtime< query::has_localtime_r::value >().call( t, r ); }

28voto

Howard Hinnant Points 59526

Tu ne rates rien.

La prochaine norme C (qui devrait sortir probablement cette année) est définie dans l'annexe K :

struct tm *localtime_s(const time_t * restrict timer,
                       struct tm * restrict result);

Et cette nouvelle fonction est thread safe ! Mais ne vous réjouissez pas trop vite. Il y a deux problèmes majeurs :

  1. localtime_s est un en option extension à la C11.

  2. C++11 fait référence à C99, pas à C11. local_time_s est introuvable en C++11, qu'elle soit optionnelle ou non.

Mise à jour

Au cours des quatre années qui se sont écoulées depuis que j'ai répondu à cette question, j'ai également été frustré par la mauvaise conception des outils C++ dans ce domaine. J'ai été motivé pour créer des outils C++ modernes pour faire face à ce problème :

http://howardhinnant.github.io/date/tz.html

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

int
main()
{
    using namespace date;
    auto local_time = make_zoned(current_zone(), std::chrono::system_clock::now());
    std::cout << local_time << '\n';
}

Ça vient de sortir pour moi :

2015-10-28 14:17:31.980135 EDT

local_time est une paire de std::chrono::system_clock::time_point y time_zone indiquant l'heure locale.

Il existe des utilitaires pour casser le std::chrono::system_clock::time_point en types de champs lisibles par l'homme, tels que l'année, le mois, le jour, l'heure, la minute, la seconde et les sous secondes. Voici une présentation qui se concentre sur ces éléments (hors fuseau horaire) :

https://www.youtube.com/watch?v=tzyGjOm8AKo

Tout ceci est bien sûr thread safe (c'est du C++ moderne).

Mise à jour 2

Ce qui précède fait maintenant partie de C++20 avec cette syntaxe légèrement modifiée :

#include <chrono>
#include <iostream>

int
main()
{
    namespace chr = std::chrono;

    chr::zoned_time local_time{chr::current_zone(), chr::system_clock::now()};
    std::cout << local_time << '\n';
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X