Forum: PC-Programmierung system_clock::now() liefert UTZ, benötige GMT + 1


von Curby23523 N. (Gast)


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
}

von Wilhelm M. (wimalopaan)


Lesenswert?

Du brauchst auch tz.h
1
    using namespace date;
2
    using namespace std::chrono;
3
    auto t = make_zoned(std::chrono::tzdb::current_zone(), system_clock::now());
4
    std::cout << t << '\n';

von Curby23523 N. (Gast)


Lesenswert?

Dann erhalte ich die exception "tz Timezone database not found".

von Wilhelm M. (wimalopaan)


Lesenswert?

Dann wird das wohl so sein, und Du hast auf Deinem System tz nicht 
korrekt konfiguriert.

von Curby23523 N. (Gast)


Lesenswert?

Ich habe date.h mit vcpkg als x86-windows-static installiert

von Oliver S. (oliverso)


Lesenswert?

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.

Oliver

von Wilhelm M. (wimalopaan)


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.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Ach so.

Wilhelm M. schrieb:
> Wobei er eigentlich nur die Header und tz.cpp braucht
> ... Also einfach die TU tz.cpp einbauen - fertig.

Das braucht die IANA time zone database. Auch da hilft vermutlich RTFM. 
Dann halt bei Howard.

Oliver

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Oliver S. schrieb:
> Ach so.
>
> Wilhelm M. schrieb:
>> Wobei er eigentlich nur die Header und tz.cpp braucht
>> ... Also einfach die TU tz.cpp einbauen - fertig.
>
> Das braucht die IANA time zone database. Auch da hilft vermutlich RTFM.

Und sowas hat M$-Windoofs nicht???

von Oliver S. (oliverso)


Lesenswert?

Das war aber jetzt ne rhetorische Frage, oder?

Oliver

von Wilhelm M. (wimalopaan)


Lesenswert?

Oliver S. schrieb:
> Das war aber jetzt ne rhetorische Frage, oder?

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 ...

von Oliver S. (oliverso)


Lesenswert?

MS hat, wenig überraschend, etwas, was sich „Microsoft Time Zone“ nennt.

Olive

von Glutenfreier Veganer von FFF, der im Lehmhaus lebt (Gast)


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.

von Wilhelm M. (wimalopaan)


Lesenswert?

Oliver S. schrieb:
> MS hat, wenig überraschend, etwas, was sich „Microsoft Time Zone“ nennt.

Ok, der Vorschlag von Howard sollte das natürlich auch benutzen. Fehlt 
also bei ihm was für die Plattform M$?

von Wilhelm M. (wimalopaan)


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.

von Oliver S. (oliverso)


Lesenswert?

Wilhelm M. schrieb:
> Ok, der Vorschlag von Howard sollte das natürlich auch benutzen. Fehlt
> also bei ihm was für die Plattform M$?

https://howardhinnant.github.io/date/tz.html#Installation

Oliver

von Wilhelm M. (wimalopaan)


Lesenswert?

Oliver S. schrieb:
> Wilhelm M. schrieb:
>> Ok, der Vorschlag von Howard sollte das natürlich auch benutzen. Fehlt
>> also bei ihm was für die Plattform M$?
>
> https://howardhinnant.github.io/date/tz.html#Installation

Genau das habe ich vermutet.

Dann sollte der TO das mal machen ;-)

von Lutz (Gast)


Lesenswert?

Curby23523 N. schrieb:
> Wie kann ich das ändern?

Einfach umrechnen. Normalerweise rechnet man intern immer mit UTC und 
rechnet dann bei Bedarf in die lokale Zeitzone um.

von Yalu X. (yalu) (Moderator)


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 ;-)

von Wilhelm M. (wimalopaan)


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.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


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)

von Wilhelm M. (wimalopaan)


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?

von Yalu X. (yalu) (Moderator)


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.

von Wilhelm M. (wimalopaan)


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.

von Yalu X. (yalu) (Moderator)


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?

von mh (Gast)


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.

von Rolf M. (rmagnus)


Lesenswert?

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. ;-)

von mh (Gast)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.