system_clock::now() liefert UTZ, benötige GMT + 1

Gast #6116183
Lesenswert?

Hallo,

mit folgender Funktion erstelle ich mir einen ISO8601 String. Leider 
liefert dieser nur die UTZ Zeit, also bei mir 9 Uhr, statt 10 Uhr. Wie 
kann ich das ändern? Ich verwende wie man sehen kann die date.h 
Bibliothek.
1
std::string getDate() {
2
  using namespace std::chrono;
3

4
  auto now = system_clock::now();
5
  return date::format("%FT%TZ", date::floor<std::chrono::milliseconds>(now));
6
}
#6117281
Lesenswert?

Oliver S. schrieb:
> RTFM.
>
> 
https://docs.microsoft.com/de-de/cpp/overview/visual-cpp-language-conformance?view=vs-2019
>
> P0355R7: <chrono> Kalender und Zeitzonen   Nein
>
> C++20 ist einfach noch nicht komplett verfügbar.

Er schreibt oben, dass er date.h verwendet, offensichtlich aus dem Repo 
von Howard. Nur seine Installation aus diesem Repo scheint eben nicht 
korrekt zu sein. Wobei er eigentlich nur die Header und tz.cpp braucht 
... Also einfach die TU tz.cpp einbauen - fertig.
Gast #6117345
Lesenswert?

Wilhelm M. schrieb:
> Ich muss leider zugeben, dass ich noch nie ein solches System benutzt
> habe, es auch nicht tun werde, und schon gar nicht darauf entwickeln
> werde. Deswegen weiß ich es wirklich nicht ...

Man stelle sich mal vor, es gibt auch Kunden deren Zielsystem Windows 
ist und das auch technologisch bedingt nicht geändert werden kann.
#6117349
Lesenswert?

Glutenfreier Veganer von FFF, der im Lehmhaus lebt schrieb im Beitrag 
#6117345:
> Man stelle sich mal vor, es gibt auch Kunden deren Zielsystem Windows
> ist und das auch technologisch bedingt nicht geändert werden kann.

Das dürfen die auch gerne verwenden. Von irgendwas muss M$ ja auch 
leben. Aber ich mache das nicht ... nicht aus Kostengründen, sondern 
weil mir die Bedienung viel zu umständlich ist, für die Dinge, die ich 
zu erledigen habe.
Moderator #6118320
Lesenswert?

Ohne die Files date.h, tz.h, tz_private.h und tz.cpp von Howard Hinnant
geht es auch out-of-the-box und standardkonform so:

1
#include <ctime>
2

3
std::string getDate() {
4
  time_t t = time(NULL);
5
  char buffer[30];
6
  strftime(buffer, sizeof buffer, "%FT%TZ", localtime(&t));
7
  return std::string(buffer);
8
}

Das ist vielleicht kein "Modern C++", funktioniert aber dafür ;-)
#6118412
Lesenswert?

Yalu X. schrieb:
> Das ist vielleicht kein "Modern C++", funktioniert aber dafür ;-)

Man es aber auch trotzdem modern, idiomatisch und richtig machen:
1
std::optional<std::string> getDate() {
2
  const time_t t{time(nullptr)};
3
  if (t == -1) return {}; 
4
  if (struct tm tm{}; localtime_r(&t, &tm) != nullptr) {
5
      if (char buffer[30]; strftime(buffer, sizeof buffer, "%FT%TZ", &tm) > 0) {
6
          return std::string{buffer};
7
      }
8
  }
9
  return {};
10
}

Wahrscheinlich sollte Dein Beispiel nur das Prinzip zeigen. Leider 
kursiert solcher Code weitläufig und wird tatsächlich irgendwo 
eingebaut.

Leider ist strftime() nicht nullptr-fest (SEGV). Und localtime() bzw. 
localtime_r() liefert nullptr bei einem Fehler. Auch time() kann einen 
Fehler liefern. Zudem war das Ganze ja nicht thread-safe.
Moderator #6118602
Lesenswert?

Wilhelm M. schrieb:
> Leider ist strftime() nicht nullptr-fest (SEGV). Und localtime() bzw.
> localtime_r() liefert nullptr bei einem Fehler. Auch time() kann einen
> Fehler liefern.

Ja, die Fehlerbehandlung fehlt in meinem Beispiel.

Wie wird das eigentlich bei std::chrono::system_clock::now(), die ja
etwas ganz Ähnliches wie time() tut, gehandhabt? Die Funktion liefert im
Fehlerfall weder eine Exception noch einen speziellen Returnwert.

Da mir persönlich die Funktionen localtime und strftime aus time.h wegen
ihrer Einschränkungen auch nicht besonders zusagen:

Wie würde man die Funktion GetDate() des TE ohne die Verwendung externer
Bibliotheken (wie bspw. die von Hinnant) standardkonform besser
implementieren?

1. in C++17

2. in C++20 (vorausgesetzt, die Standardbibliothek ist vollständig
   implementiert)
#6118621
Lesenswert?

Yalu X. schrieb:
> Wie wird das eigentlich bei std::chrono::system_clock::now(), die ja
> etwas ganz Ähnliches wie time() tut, gehandhabt? Die Funktion liefert im
> Fehlerfall weder eine Exception noch einen speziellen Returnwert.

Liefert ein "ungültiges" Objekt, d.h. time_since_epoch() == 0.

Yalu X. schrieb:
> Wie würde man die Funktion GetDate() des TE ohne die Verwendung externer
> Bibliotheken (wie bspw. die von Hinnant) standardkonform besser
> implementieren?
>
> 1. in C++17

Hatte ich ja geschrieben.

Yalu X. schrieb:
> 2. in C++20 (vorausgesetzt, die Standardbibliothek ist vollständig
>    implementiert)

Steht eigentlich auch schon oben in meinem Beitrag.

Oder worauf willst Du bei Deinen Fragen hinaus?
Moderator #6118729
Lesenswert?

Wilhelm M. schrieb:
> Oder worauf willst Du bei Deinen Fragen hinaus?

localtime() erscheint mir wegen des statischen Ergebnispuffers etwas
altbacken. localtime_r() behebt diesen Mangel, ist aber Unix-spezifisch.

strftime() gefällt mir nicht so gut, weil man dafür ein C-Array
ausreichender Größe als Ergebnispuffers bereitstellen muss. Das ist für
C-Programme in Ordnung. Wenn man aber in einem C++-Programm das Ergebnis
als std::string haben möchte, erscheint mir der Umweg über den C-String
etwas holprig, zumal man bei einer Änderung des Formatstrings evtl. auch
die Größe des Ergebnispuffers anpassen muss.

Die Bibliothek von Hinnant kommt ohne diese Funktionen aus, ist aber
nicht standardisiert.

Deswegen würde es mich interessieren, ob die C++-Standardbibliothek
mittlerweile modernere Alternativen für localtime() und strftime()
anbietet.

Einen Ersatz für strftime() habe ich inzwischen gefunden, nämlich
std::put_time() in Verbindung mit einem std::stringstream. Die
Verwendung ist zwar ähnlich umständlich wie bei strftime(), aber
immerhin entfällt die manuelle Dimensionierung des Ergebnispuffers.

Für localtime() habe ich in C++17 keine Alternative gefunden. In C++20
wird <chrono> um Zeitzonenfunktionen erweitert, nur ist mir nicht ganz
klar, wie diese zu verwenden sind. Ich kann dazu leider auch  nichts
ausprobieren, da die Zeitzonen in std::chrono von GCC 9.2 noch nicht
implementiert sind.
#6118870
Lesenswert?

Yalu X. schrieb:
> localtime() erscheint mir wegen des statischen Ergebnispuffers etwas
> altbacken.

Sollte man wegen des globalen Buffers dann auch ohne Synchronisation 
nicht in MT-Code verwenden.

Yalu X. schrieb:
> localtime_r() behebt diesen Mangel, ist aber Unix-spezifisch.

Ist genau genommen IEEE1003.1 (also Posix) und wird dann C2x werden.

Yalu X. schrieb:
> strftime() gefällt mir nicht so gut, weil man dafür ein C-Array
> ausreichender Größe als Ergebnispuffers bereitstellen muss. Das ist für
> C-Programme in Ordnung. Wenn man aber in einem C++-Programm das Ergebnis
> als std::string haben möchte, erscheint mir der Umweg über den C-String
> etwas holprig, zumal man bei einer Änderung des Formatstrings evtl. auch
> die Größe des Ergebnispuffers anpassen muss.

Sehe ich auch so. Aber auf der anderen Seite macht man den Puffer eben 
maximal groß bzw. ist er zu klein, meldet das strftime ja als Fehler.

Yalu X. schrieb:
> Die Bibliothek von Hinnant kommt ohne diese Funktionen aus, ist aber
> nicht standardisiert.

So wird es aber dann in C++20 werden, das Paper ist angenommen.

Yalu X. schrieb:
> Deswegen würde es mich interessieren, ob die C++-Standardbibliothek
> mittlerweile modernere Alternativen für localtime() und strftime()
> anbietet.

Schau in den Coe von H.H, er bildet im Grunde genommen in to_stream(...) 
strftime() nach.

Yalu X. schrieb:
> Ich kann dazu leider auch  nichts
> ausprobieren, da die Zeitzonen in std::chrono von GCC 9.2 noch nicht
> implementiert sind.

Nimm einfach das Repo von H.H.
Moderator #6118902
Lesenswert?

Wilhelm M. schrieb:
> Yalu X. schrieb:
>> Die Bibliothek von Hinnant kommt ohne diese Funktionen aus, ist aber
>> nicht standardisiert.
>
> So wird es aber dann in C++20 werden, das Paper ist angenommen.

Im Draft N4849 von 2020-01-14 kann ich bspw. die Funktion make_zoned
nicht finden. Daran wird sich vermutlich auch nicht mehr viel ändern.
Oder hat die Funktion vielleicht nur einen anderen Namen bekommen?
Gast #6119137
Lesenswert?

Wilhelm M. schrieb:
> Yalu X. schrieb:
>> Wie wird das eigentlich bei std::chrono::system_clock::now(), die ja
>> etwas ganz Ähnliches wie time() tut, gehandhabt? Die Funktion liefert im
>> Fehlerfall weder eine Exception noch einen speziellen Returnwert.
>
> Liefert ein "ungültiges" Objekt, d.h. time_since_epoch() == 0.
 Ernsthaft? Wie soll man dann dieses ungültige Objekt von einem gültigen 
unterscheiden? Oder ist die epoch kein gültiger Wert für die zugehörige 
Uhr? Wo genau kann ich das nachlesen? Ich konnte nichts im Draft des 
Standards, in dem ich gesucht habe (https://eel.is/c++draft/), finden. 
Auch auf cppreference finde ich nichts dazu.
Gast #6119414
Lesenswert?

Rolf M. schrieb:
> mh schrieb:
>>> Liefert ein "ungültiges" Objekt, d.h. time_since_epoch() == 0.
>>  Ernsthaft? Wie soll man dann dieses ungültige Objekt von einem gültigen
>> unterscheiden? Oder ist die epoch kein gültiger Wert für die zugehörige
>> Uhr?
>
> Zumindest nicht für now(), es sei denn, du hast eine Zeitmaschine. ;-)

Das mag vielleicht für system_clock und co. auf den ersten Blick 
zutreffen, aber sobald jemand an der Systemzeit dreht ... Und ja, ich 
kenne Systeme, bei denen die Systemzeit auf einen Zeitpunkt in der 
fernen Vergangheit zurück gedreht wird. Ich habe bist jetzt auch keine 
Bedingung gefunden, die einen zukünftigen Zeitpunkt als epoch 
ausschließt.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren