Betrachten Sie den folgenden C ++ - Code
#include <ctime>
#include <iostream>
int main()
{
std::time_t now = std::time(nullptr);
struct tm local = *std::localtime(&now);
struct tm gm = *std::gmtime(&now);
char str[20];
std::strftime(str, 20, "%Z", &local);
std::cout << str << std::endl; // HKT
std::strftime(str, 20, "%Z", &gm);
std::cout << str << std::endl; // UTC
return 0;
}
So gespeichert now
ist ein eindeutiger Integralwert, während local
und gm
sind , struct tm
dass Speicher für Menschen lesbaren Datum / Uhrzeit. Dann drucke ich die formatierten Informationen (Zeitzone) nur basierend auf den struct tm
Objekten aus.
Gemäß der cplusplus Referenz der Datenelemente struct tm
sind ,
tm_sec
tm_min
tm_hour
tm_mday
tm_mon
tm_year
tm_wday
tm_yday
tm_isdst
Wenn das alles ist, was a struct tm
enthält, woher weiß das Programm, dass die Zeitzoneninformationen daraus stammen? Das heißt, woher weiß es, dass die Zeitzone HKT
für local
und die Zeitzone UTC
für ist gm
?
Wenn das nicht alles ist, was ein struct tm
enthält, erklären Sie bitte, wie es Zeitzoneninformationen speichert.
Übrigens, obwohl der Demo-Code in C ++ ist, denke ich, dass diese Frage im Wesentlichen auch eine legitime C-Frage ist.
tm
enthält keine Zeitzoneninformationen.strftime
Erhält die Zeitzone durch Voodoo hinter den Kulissen. Wenn Sie die Zeitzone im Allgemeinen erhalten möchten, ist das ein bisschen chaotisch. Es gibt ( derzeit ) keine Standardmethode, um eine Zeitzone zu erhalten. Zum Glück Howard Hinnant ist auf diesem Job ... .tm
Woherstrftime
weiß man angesichts aller darin gespeicherten Informationen , wie man auf zweistruct tm
Objekte unterschiedlich reagiert ? Es sei denn ,tm
enthält einige Informationen wie diesetm
erstellt wirdlocaltime
, dietm
erstellt wirdgmtime
.tm
Struktur speichert keine Zeitzonen-Infos. Warum glauben Sie, dass dies der Fall ist? Der Unterschied liegt eher in den Anrufen zugmtime()
undlocaltime()
.strftime
die Saugnäpfe auseinanderhalten. Sollte hinzufügen, dass POSIX das, was passiert, undefiniert lässt.tm
s mit zusätzlichen Informationen gesehen hatte. Hier ist einer . Beachten Sie dasconst char *tm_zone
Mitglied. Für welche Plattform kompilieren Sie? Schauen Sie sich dietm
Implementierung an, um festzustellen, ob sie die Struktur erweitert hat.Antworten:
Der C-Standard sagt in 7.27.1 Komponenten der Zeit:
(Schwerpunkt liegt bei mir)
Das heißt, Implementierungen können zusätzliche Mitglieder hinzufügen
tm
, wie Sie bei gefunden habenglibc/time/bits/types/struct_tm.h
. Die POSIX-Spezifikation hat einen nahezu identischen Wortlaut.Das Ergebnis ist, dass
%Z
(oder sogar%z
) nicht als tragbar in betrachtet werden kannstrftime
. Die Spezifikation für%Z
spiegelt dies wider:Das heißt, Anbieter dürfen ihre Hände hochwerfen und einfach sagen: "Es war keine Zeitzone bestimmbar, daher gebe ich überhaupt keine Zeichen aus."
Meine Meinung: Die C-Timing-API ist ein Chaos.
Ich versuche, die Dinge für den kommenden C ++ 20-Standard in der
<chrono>
Bibliothek zu verbessern .Die C ++ 20-Spezifikation ändert dies von "keine Zeichen" in eine Ausnahme, die ausgelöst wird, wenn die
time_zone
Abkürzung nicht verfügbar ist:http://eel.is/c++draft/time.format#3
Abgesehen davon, dass der obige Absatz keine Cs beschreibt
strftime
, sondern eine neueformat
Funktion, die mitstd::chrono
Typen arbeitet, nichttm
. Zusätzlich gibt es einen neuen Typ:std::chrono::zoned_time
( http://eel.is/c++draft/time.zone.zonedtime ), der immer dietime_zone
Abkürzung (und den Offset) zur Verfügung hat und mit der oben genanntenformat
Funktion formatiert werden kann.Beispielcode:
(Haftungsausschluss: Die endgültige Syntax der Formatierungszeichenfolge in der
format
Funktion unterscheidet sich wahrscheinlich geringfügig, die Funktionalität ist jedoch vorhanden.)Wenn Sie mit einer Vorschau dieser Bibliothek experimentieren möchten, ist diese hier kostenlos und Open Source: https://github.com/HowardHinnant/date
Einige Installationen sind erforderlich: https://howardhinnant.github.io/date/tz.html#Installation
In dieser Vorschau müssen Sie den Header verwenden
"date/tz.h"
, und der Inhalt der Bibliothek befindet sichnamespace date
anstelle vonnamespace std::chrono
.Die Vorschau-Bibliothek kann mit C ++ 11 oder höher verwendet werden.
zoned_time
wird auf einer Vorlage erstellt,std::chrono::duration
die die Genauigkeit des Zeitpunkts angibt, und im obigen Beispielcode mithilfe der CTAD-Funktion von C ++ 17 abgeleitet . Wenn Sie diese Vorschau-Bibliothek in C ++ 11 oder C ++ 14 verwenden, sieht die Syntax eher so aus:Oder es gibt eine nicht für die Standardisierung vorgeschlagene Hilfsfabrikfunktion, die den Abzug für Sie übernimmt:
(#CTAD_eliminates_factory_functions)
quelle
Vielen Dank für alle Kommentare zu der Frage, die helfen, in die richtige Richtung zu weisen. Ich poste einige meiner eigenen Forschungen unten. Ich spreche basierend auf einem archivierten Repo der GNU C Library, das ich auf dem GitHub gefunden habe. Seine Version ist
2.28.9000
.Da
glibc/time/bits/types/struct_tm.h
drin istEs scheint, dass
struct tm
zumindest in dieser Implementierung Zeitzoneninformationen gespeichert werden.quelle
Einer der Gründe, warum Datums- und Zeitprogrammierung so schwierig ist, ist, dass es grundsätzlich zumindest ein etwas schwieriges Problem ist: "Dreißig Tage hat September", sexagesimale Arithmetik , Zeitzonen, Sommerzeit und Schaltjahre, und lassen Sie uns nicht einmal Sprechen Sie über Schaltsekunden.
Aber der andere Grund, warum es schwierig ist, ist, dass allzu viele Bibliotheken und Sprachen ein perfektes Durcheinander daraus machen, und C ist leider keine Ausnahme. (C ++ versucht es besser zu machen, wie Howard in seiner Antwort erwähnt.)
Obwohl jeder weiß, dass globale Variablen schlecht sind, verwenden die Datums- / Zeitfunktionen von C im Grunde genommen einige davon. Tatsächlich ist das Konzept der "aktuellen Zeitzone dieses Systems" eine globale Variable, und die globalen Daten, die diese Zeitzone beschreiben, werden wohl
localtime
und übel zwischen undstrftime
und einer Reihe anderer Funktionen geteilt.So
strftime
füllen kann%z
und%Z
auf diesen globalen Daten basieren, auch wenn es nicht in als Teil eines übergeben wirdstruct tm
Wertes.Das ist offensichtlich eine suboptimale Anordnung, und es würde echte Probleme verursachen, wenn ein Programm die Zeitzone, für die es verwendet werden möchte, und den Rest dynamisch ändern könnte
localtime
. (Und diese Anordnung bleibt teilweise bestehen, weil es für ein Programm keine gute, tragbare Standardmethode gibt, um die lokale Zeitzone zu ändern, die es verwendet.)Im Laufe der Jahre gab es verschiedene halbherzige Versuche, einen Teil des Chaos zu beseitigen (wobei natürlich die Abwärtskompatibilität erhalten blieb). Einer dieser Versuche betrifft die erweiterten Felder
tm_gmtoff
undtm_zone
Felder, die Sie in einigen Systemversionen von entdeckt habenstruct tm
. Diese Ergänzungen sind eine enorme Verbesserung - ich kann mir nicht vorstellen, ernsthafte Datums- / Zeitprogramme auf einem System ohne sie durchzuführen -, aber sie sind immer noch nicht Standard, und es gibt immer noch viele Systeme, die sie nicht haben (nicht einmal) mit den "versteckten" Schreibweisen__tm_gmtoff
und__tm_zone
).In diesem Artikel können Sie viel mehr über die schmutzige Geschichte der Datums- / Zeitunterstützung in C lesen: Zeit-, Uhr- und Kalenderprogrammierung in C von Eric Raymond.
quelle