Probleme bei der Zeitumstellung

Im laufenden Betrieb bekommt ein Programm die Zeitumstellung nicht mit — ein kleiner Befehl schafft Abhilfe.

Ein Artikel von Michael Fuchs.
Getestet mit Lazarus 3.2 | FPC 3.2.2

Jeden Tag um 12:00 Uhr sendet mir ein kleines Programm eine Statusmeldung. Doch am 30. März 2025 kam diese Nachricht erst um 13:00 Uhr.

Da in der Nacht die Umstellung auf die Sommerzeit erfolgte, war die erste Vermutung: der Server läuft noch auf Winterzeit. Es stellte sich jedoch schnell heraus, dass die Systemzeit korrekt war. Ein zwischenzeitlicher Neustart brachte Abhilfe — am 1. April kam die Meldung wie gewünscht wieder um 12:00 Uhr.

Dieses Verhalten beruht auf der Behandlung von Zeitangaben durch Unix und Linux (bei Windows-Systemen tritt das Problem nicht auf). Intern wird UTC-Zeit verwendet. Bei einer Ausgabe für den Benutzer muss das Offset der eingestellten Zeitzone addiert werden.

Die Freepascal-Bibliotheken addieren dieses Offset automatisch, müssen dazu aber die korrekte Zeitzone und den Status der Sommerzeit kennen — und diese Daten werden nur einmal beim Programmstart geladen.

Lösung

Aber natürlich haben die FPC-Entwickler auch eine Lösung für unser Problem. In der Unit Unix ist die Prozedur ReReadLocalTime enthalten, die im laufenden Programm die Zeitzoneninformationen aktualisiert.

Rufen wir diese nach Umstellung der Sommer- oder Winterzeit auf, sind alle nachfolgenden Zeitangaben wieder korrekt.

Performance

Wer nun als grundsätzlich Lösung vor jede Zeitabfrage ein ReReadLocalTime setzen möchte sei gewarnt: dies verzehnfacht die Laufzeit einer Zeitabfrage. Dies ist auch der Grund dafür, dass die Informationen nur einmal beim Programmstart abgerufen werden.

Wir müssen also selber entscheiden an welchen Stellen ein erneutes Auslesen der Zeitzoneninformationen passend ist. Wenn – beispielsweise bei einem ausführlichen Logging – im Millisekundentakt Zeitabfragen geschehen ist Vorsicht geboten.

Wird die Zeit hingegen stündlich abgefragt und es liegen keine gesteigerten Performance-Anforderung vor, dann ist eine Lösung über eine eigene Zeitfunktion durchaus brauchbar:

function DstAwareNow: TDateTime;
begin
  ReReadLocalTime;
  Result := Now;
end;