Je fournis une réponse supplémentaire au cas où quelqu'un voudrait le faire d'une manière qui soit sûre pour les threads (sans définir de variable globale comme une variable d'environnement). Cette réponse nécessite C++ 11 (ou mieux) et Howard Hinnant's free, open-source timezone library, qui a été porté sur linux, macOS et Windows.
Cette bibliothèque se base sur <chrono>
, en l'étendant aux calendriers et aux fuseaux horaires. On peut s'interfacer avec l'API de synchronisation C telle que struct tm
avec cette bibliothèque, mais de telles fonctionnalités ne sont pas intégrées à la bibliothèque. Cette bibliothèque rend l'API C inutile, sauf si vous devez vous interfacer avec un autre code qui utilise l'API C.
Par exemple, il est un type appelé date::zoned_seconds
que les couples un system_clock::time_point
(sauf avec précision seconds
) avec un date::time_zone
pour créer l'heure locale dans une zone de temps arbitraire. Comme described in more detail here, voici comment vous pouvez convertir un zoned_seconds
en std::tm
:
std::tm
to_tm(date::zoned_seconds tp)
{
using namespace date;
using namespace std;
using namespace std::chrono;
auto lt = tp.get_local_time();
auto ld = floor<days>(lt);
time_of_day<seconds> tod{lt - ld}; // <seconds> can be omitted in C++17
year_month_day ymd{ld};
tm t{};
t.tm_sec = tod.seconds().count();
t.tm_min = tod.minutes().count();
t.tm_hour = tod.hours().count();
t.tm_mday = unsigned{ymd.day()};
t.tm_mon = unsigned{ymd.month()} - 1;
t.tm_year = int{ymd.year()} - 1900;
t.tm_wday = unsigned{weekday{ld}};
t.tm_yday = (ld - local_days{ymd.year()/jan/1}).count();
t.tm_isdst = tp.get_info().save != minutes{0};
return t;
}
L'utilisation de ce bloc de construction, il devient presque trivial de convertir un time_t
à un tm
dans une zone de temps arbitraire (sans définir global):
std::tm
localtime_tz(time_t t, const std::string& timezone)
{
using namespace date;
using namespace std::chrono;
return to_tm({timezone, floor<seconds>(system_clock::from_time_t(t))});
}
Si vous utilisez 17 C++, vous pouvez supprimer using namespace date
comme floor<seconds>
sera complètement prévu à l'intérieur namespace std::chrono
.
Le code ci-dessus crée un zoned_seconds
du string
timezone
et un system_clock::time_point
dérivé du time_t
t
. Le zoned_seconds
est conceptuellement un pair<time_zone, system_clock::time_point>
mais de précision arbitraire.Et il peut également être considéré comme un pair<time_zone, local_time>
puisque le time_zone
sait comment faire la carte entre l'UTC et l'heure locale. Donc, la plupart du code écrit par l'utilisateur ci-dessus consiste simplement à extraire l'heure locale du zoned_seconds
et à le placer dans un struct tm
.
Le code ci-dessus peut être exercé comme ceci:
auto tm = localtime_tz(time(nullptr), "America/Anchorage");
Si vous n'avez pas besoin le résultat dans un tm
mais peut rester à la place dans le système <chrono>
, il existe de très belles caractéristiques du timezone library pour l'analyse syntaxique et le formatage du zoned_seconds
, par exemple:
cout << zoned_seconds{"America/Anchorage", floor<seconds>(system_clock::now())} << '\n';
sortie de l'échantillon:
2017-08-10 16:50:28 AKDT