web-dev-qa-db-fra.com

une langue C++ a-t-elle un fuseau horaire associé? Et si oui, comment y accédez-vous?

J'ai fait une petite recherche à ce sujet et j'ai des preuves assez convaincantes pour la réponse OUI, et la réponse NON. Je ne sais pas de quel côté croire.

Tout d'abord, la documentation que j'ai trouvée sur cppreference.com, et http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf semble être ne rien dire à ce sujet ... Je considère cela comme une preuve que les paramètres régionaux ne prennent PAS en charge un fuseau horaire.

Mais https://en.cppreference.com/w/cpp/locale/time_get/get et https://en.cppreference.com/w/cpp/locale/time_put/put les deux disent:

% z écrit en décalage par rapport à UTC au format ISO 8601 (par exemple, -0430) ou n °. caractères si les informations de fuseau horaire ne sont pas disponibles.% Z écrit nom ou abréviation du fuseau horaire, ou pas de caractères si le fuseau horaire l'information n'est pas disponible (dépend des paramètres régionaux) 

qui semble suggérer qu’il existe parfois un fuseau horaire associé à un objet locale ().

Maintenant, si vous prenez les paramètres régionaux en_US.utf8 (un de mes favoris ;-)), il n’ya vraiment aucun fuseau horaire raisonnable à associer (les États-Unis contiennent au moins 4 fuseaux horaires).

Il est donc temps d’être empirique.

J'ai couru le code:

#include <iostream>
#include <cstdlib>
#include <locale>
#include <sstream>
using namespace std;
int main ()
{
    //  locale l;
    locale                l = locale::classic ();
    tm                    when{};
    const time_put<char>& tmput = use_facet<time_put<char>> (l);
    ostringstream         oss;
    oss.imbue (l);
    static const string   kTZOffsetPattern_{"%z"};
    tmput.put (oss, oss, ' ', &when, kTZOffsetPattern_.c_str (), kTZOffsetPattern_.c_str () + kTZOffsetPattern_.length ());
    cout << oss.str ();
    return 0;
}

Sous Linux (ubuntu), cela donnait la réponse à laquelle je m'attendais, +0000 (OK, je n'aurais pas été surpris non plus par une erreur ou une chaîne vide).

Mais sous Windows (visual studio.net 2k17 - 15.8.7), cela donne: -0500

Oui, comme vous l'avez peut-être deviné, je teste cela dans le fuseau horaire est. Mais je m'attendrais toujours à 0, ou à la chaîne vide (en particulier pour la casse locale :: classic ()).

16
Lewis Pringle

Réponse directe à votre question

Un environnement local C++ a-t-il un fuseau horaire associé?

Non.

Ce ne sera pas le cas à l'avenir. Comme indiqué à juste titre dans la question, pour de nombreux paramètres régionaux, cela n'aurait aucun sens puisque la zone géographique représentée par les paramètres régionaux peut avoir plusieurs fuseaux horaires.

La norme C dit dans la spécification de strftime:

%Z est remplacé par le nom ou l'abréviation du fuseau horaire de l'environnement local, ou par l'absence de caractères si non le fuseau horaire est déterminable. [tm_isdst]

Mais la spécification C pour struct lconv ne fournit aucun membre de ce type pour stocker ces informations. La spécification autorise les implémentations à ajouter de tels membres, mais en pratique, les implémentations ne stockent pas ces informations avec les paramètres régionaux C.

Les facettes de paramètres régionaux C++ time_put et time_get se définissent en fonction de la spécification C pour strftime, de la spécification POSIX pour strptime et de certains ajouts, qui n'incluent pas de nom de fuseau horaire ni d'abréviation.

La spécification POSIX pour strftime est beaucoup plus détaillée que la spécification C et supprime l'association avec "locale":

Z Remplacé par le nom ou l'abréviation du fuseau horaire, ou par aucun octet s'il n'existe aucune information de fuseau horaire. [ tm_isdst]

La spécification POSIX pour struct lconv est également beaucoup plus détaillée que la spécification C, mais ne fournit toujours pas de stockage pour un nom de fuseau horaire ou une abréviation.

Mais l'avenir laisse espérer un accès plus facile et efficace aux informations sur les fuseaux horaires, du moins en C++.

Avant C++ 20, C++ connaissait:

  1. Une seule norme de temps: UTC, qui est étroitement modelée par Unix Time .

  2. Un seul fuseau horaire: le "fuseau horaire local" défini par l'utilisateur ou l'administrateur de l'ordinateur. UTC peut également être utilisé comme fuseau horaire local.

Comme indiqué ci-dessus, le fuseau horaire local fait non une partie des données de paramètres régionaux C++ (ou C). Les données de paramètres régionaux fait incluent des données calendaires telles que:

  • Noms de semaine complets et abrégés.
  • Noms de mois complets et abrégés.
  • Formats conventionnels locaux pour l’affichage de la date et de l’heure (par exemple, année, mois, ordre du jour).

L'abréviation du décalage horaire (%z) et du fuseau horaire (%Z) peut est disponible, mais elle serait stockée dans les données de fuseau horaire local, au lieu des données de paramètres régionaux en cours bonne correspondance individuelle entre les fuseaux horaires et les paramètres régionaux.

Explication de ce qui s'est passé avec le code présenté dans la question du PO

Dans votre exemple: tm when{}; remet à zéro tous les membres de la tm, y compris tm_isdst. Lorsque tm_isdst est égal à zéro, cela signifie que l'heure d'été est réputée ne pas être en vigueur pour cette tm particulière.

tm est également autorisé à avoir des membres non spécifiés par la norme. Une extension populaire consiste à avoir un membre tm_gmtoff qui contient le décalage UTC en secondes. Si votre implémentation Linux a un tel membre, tm when{}; l'aurait définie sur 0 seconde. Si votre implémentation Windows a un tel membre non, le décalage UTC du fuseau horaire local serait stocké ailleurs. Cela explique les différences que vous constatez et que les deux implémentations sont conformes.


Informations utiles sur l'accès aux fuseaux horaires, car les environnements locaux C++ ne fournissent pas d'accès

Dans le brouillon de la spécification C++ 20, il existe un nouveau type appelé std::chrono::time_zone. Une des fonctions membres de time_zone est:

template<class Duration> sys_info get_info(const sys_time<Duration>& st) const;

sys_time<Duration> est juste un system_clock::time_point, mais de précision toute. Donc, vous donnez à time_zone un time_point et vous récupérez un sys_info qui contient toutes sortes d'informations utiles sur thattime_zone à thattime_point:

struct sys_info
{
    sys_seconds begin;
    sys_seconds end;
    seconds     offset;
    minutes     save;
    string      abbrev;
};
  • La plage [begin, end) vous indique à quelle heure cette information est valide (il s’agit des points horaires UTC).
  • offset est le décalage UTC actuel du time_zone dans seconds.
  • Si save != 0min, le time_zone est actuellement considéré comme étant en heure avancée.
  • L'abréviation actuelle de time_zone est stockée dans abbrev.

De plus, il existe une fonction non membre:

const time_zone* current_zone();

qui renvoie un pointeur sur votre fuseau horaire local. En résumé, voici un programme C++ 20 qui affiche des informations intéressantes sur votre fuseau horaire local actuel:

#include <chrono>
#include <iostream>

int
main()
{
    using namespace std::chrono;
    std::cout << current_zone()->get_info(system_clock::now()) << '\n';
}

Cette sortie vient pour moi:

2018-03-11 07:00:00
2018-11-04 06:00:00
-04:00:00
01:00
EDT

Si vous le souhaitez, vous pouvez expérimenter cette partie de C++ 20 en utilisant C++ 11, 14 ou 17 en utilisant la bibliothèque de fuseaux horaires de Howard Hinnant . Cette bibliothèque place tout dans l'espace de noms date au lieu de std::chrono.

Vous pouvez également obtenir des informations sur n'importe lequelle fuseau horaire IANA , par exemple:

#include "date/tz.h"
#include <chrono>
#include <iostream>

int
main()
{
    using namespace date;
    using namespace std::chrono;
    std::cout << locate_zone("Australia/Sydney")->get_info(system_clock::now()) << '\n';
}

qui vient de sortir pour moi:

2018-10-06 16:00:00
2019-04-06 16:00:00
11:00:00
01:00
AEDT

Notez cependant que même dans C++ 20, les fuseaux horaires et les paramètres régionaux sont non couplés. Cela n'a aucun sens de le faire.

10
Howard Hinnant

une langue C++ a-t-elle un fuseau horaire associé?

Tous les aspects du fuseau horaire actuel sont définis par la mise en œuvre.

La formulation exacte du spécificateur %Z de C99 (la spécification de la fonction de bibliothèque C déléguée C++ au standard C) est la suivante:

est remplacé par le nom ou l’abréviation du fuseau horaire de l’environnement local, ou par aucun caractère si aucun fuseau horaire n’est déterminable.

Cela semble un peu ambigu. Une interprétation est en effet que les paramètres régionaux peuvent affecter le fuseau horaire. Un autre problème, qui ne correspond pas tout à fait au libellé, serait que les paramètres régionaux affectent le nom ou l’abréviation du fuseau horaire. Quoi qu'il en soit, rien ne semble garantir que le fuseau horaire n'est pas affecté par les paramètres régionaux, bien que je ne m'attende pas à ce qu'il le soit.


comment y accédez-vous?

Autant que je sache, vous ne pouvez pas utiliser les utilitaires de bibliothèque standard. Pas directement de toute façon, et aucun moyen de le modifier.

Une façon d’imprimer le fuseau horaire actuel consiste à utiliser les spécificateurs de format %z ou %Z de strftime/put_time/time_put comme vous l’avez montré.

Il existe également un moyen d’obtenir la différence de zone sous forme d’entier. std::mktime décompose une structure std::tm dans un horodatage en fonction des paramètres régionaux, alors que std::gmtime analyse un horodatage dans la structure std::tm en fonction du code UTC. Ainsi, si vous commencez avec Epoch et combinez ces deux paramètres, le UTC en secondes.

std::time_t t = 0;
std::cout << -1 * std::mktime(std::gmtime(&t));
3
eerorika

Le passage pertinent de la norme C (sur laquelle s'appuie la norme C++) dit:

% z est remplacé par le décalage par rapport à UTC au format ISO 8601 «‘ -0430 »(c’est-à-dire 4 heures et demie en retard par rapport à UTC, à l’ouest de Greenwich) ou par aucun caractère si aucun fuseau horaire n’est déterminable. [tm_isdst]

% Z est remplacé par le nom ou l’abréviation du fuseau horaire de l’environnement local, ou par aucun caractère si aucun fuseau horaire n’est déterminable. [tm_isdst]

Notez que le fuseau horaire nom est dit dépendant des paramètres régionaux, mais que le fuseau horaire offset ne l’est pas.

Cppreference doit remédier à leur formulation bâclée.

0
n.m.