Missing Values und die Sommerzeitumstellung: Anekdoten aus dem wahren Leben im Umgang mit fehlenden Werten: taktisch, manipulativ, ignorant, professionell, oder gar blitzschnell…
Am 27. März um 2:00 Uhr nachts müssen wir wieder unsere Uhren auf die Sommerzeit umstellen. Unabhängig davon, ob dieser Vorgang vom Einzelnen, der Gesellschaft oder der Wirtschaft positiv bzw. negativ bewertet wird, kann er einige „Verwerfungen“ mit sich bringen. Das liegt meist daran, dass Vielen die richtige Nutzung der Werkzeuge der Zeitanzeige und Zeitfunktionen zu unhandlich und kompliziert erscheint.
Auch wird die schweigende Mehrheit sich berechtigterweise damit begnügen, die Lösung des Problems anderen zu überlassen, um im Schlafe so wenig wie möglich von diesen unangenehmen nächtlichen Zeit-Manipulationen beeinträchtigt zu werden. Denn schon die verkürzte Nacht wird als eine Zumutung für den Biorythmus empfunden. Die Zeit hängt aber auch vom Raum bzw. dem geografischen Ort ab. Daher ist das Ganze meist nicht damit getan mal kurz die Uhr zu stellen.
Für IT-Systeme, aber auch schon beim Smartphone erzeugt die Zeitumstellung im Frühjahr eventuell fehlende Zeitwerte, oder im Herbst Zeitwertverdopplungen. Dabei gibt es auch in der SAS Software effiziente Funktionen und Methoden, um die Zeitumstellung professionell zu behandeln, so dass es gar nicht erst zu diesen Problemen kommt.
Da wären:
- Angabe der Zeitzone für jeden Datetime Wert, denn die Zeitumstellung ist nicht global, sondern zeitzonenspezifisch also lokal festgelegt.
- Die Anzeige der Datetime Variablen im ISO 8601 Standard der Coordinate Universal Time (UTC). Hierbei wird jede Zeitangabe in der mittleren Sonnenzeit am Greenwicher Nullmeridian angegeben und mit einem Stunden-Offset für die Transformation in die lokal geltende Zeitzone erweitert. Die Zeitanzeige wird also in eine simple Kopfrechenaufgabe verwandelt, z.B. „27Mar2022:08:00+1“ bedeutet „27 März 2022 um 8 Uhr Greenwicher Zeit plus 1 Stunde“ , also 27 März 2022 um 9 Uhr lokale Zeit.
- Die Nutzung einer Funktion, die aus einem UTC Datumswert den dazugehörige lokal geltenden Stunden-Offset extrahiert
- Die Nutzung einer Funktion, die aus einem UTC Datumswert die dazugehörige lokal geltende Zeitzone extrahiert.
- Die Umrechnungsfunktion, die einen lokalen UTC Zeitwert in den Greenwicher UTC Zeitwert transformiert.
- Die Rück- Transformation, die den Greenwicher UTC Zeitwert in die lokale UTC Zeit transformiert.
Anbei ein kommentiertes Code Beispiel zu den 6 Punkten vor und während der Zeitumstellung:
*1; options timezone='Europe/Berlin';
data _null_;
do Datetime_Berlin="27Mar2022:01:00"dt to "27Mar2022:03:00"dt by 3600;
put ' ';
Rohwert=put(Datetime_Berlin,f10.);put ' ' Rohwert=;
Datetime=put(Datetime_Berlin,datetime15.);put ' ' Datetime=;
*2; E8601LX=put(Datetime_Berlin,E8601LX.);put ' ' E8601LX=;
*3; Offset=TZONEOFF(Datetime_Berlin);put ' ' Offset= '[Minuten]';
*4; TimeZone=tzonename(Datetime_Berlin);put ' ' TimeZone=;
*5; TZONES2U=put(TZONES2U(Datetime_Berlin),E8601LX.);put ' ' TZONES2U=;
*6; TZONEU2S=put(TZONEU2S(Datetime_Berlin),E8601LX.);put ' ' TZONEU2S=;
end;
run;
Wer im Minutentaktung die hellblau hinterlegten Problemzonen der Zeitumstellungen nachvollziehen möchte, der kann das Ganze in der folgenden grafischen und tabellarischen Aufstellung anschauen und studieren. Durch Klick auf die Grafik erhält man eine schärfere Darstellung. Der vollständige Programmcode dazu ist weiter unten aufgeführt.
Ich hoffe diese etwas sehr technischen Details bereiten Ihnen keine schlaflose Nacht. Aber ich kann Sie beruhigen, denn erstens wissen Sie jetzt, dass Sie mit der SAS Software das Problem professionell behandeln können (wenn Sie es denn wollen), und zweitens gibt es immer noch die Möglichkeit, dass die Sommerzeitumstellung in der Europäischen Union abgeschafft wird. Den Richtlinienvorschlag dazu hat das Europäische Parlament schon 2019 abgesegnet. Seitdem liegt der Vorschlag noch beim europäischen Rat zur Entscheidung. Also genießen Sie das Ereignis der Zeitumstellung in der Nacht vom 26. Auf den 27. März. Vielleicht ist es die letzte Sommerzeitumstellung Ihres Lebens, von der Sie noch später noch mit großen Augen ihren Enkeln erzählen werden. Wer weiß?
options timezone='Europe/Berlin';
data Fruhjahr;
Format Datetime15_Format Anzeige_Funkuhr_DE datetime15. Offset time2.;
Format E8601LX_Format E8601LX.;
Rohwert_SAS="26Mar2022:24:00"dt;
do i=1 to 215;
Rohwert_SAS =intnx('Minute', Rohwert_SAS,1);
Datetime15_Format= Rohwert_SAS;
E8601LX_Format= Rohwert_SAS;
Offset=TZONEOFF(Rohwert_SAS);
TimeZone=tzonename(Rohwert_SAS);
Anzeige_Funkuhr_DE= datetime15_Format+Offset-3600;
output;
end;
run;
ods html close;
ods html;
Title "Coordinated Universal Time (UTC) Zeitformat gegenüber Funkuhr in Deutschland: Beispiel Zeitumstellung am 27 März 2022, Timezone=Europe/Berlin";
ods layout gridded columns=2;
ods graphics on / height=335 width=550;
ods region;
proc sgplot data=Fruhjahr;
title;footnote;
band y=E8601LX_Format upper="27Mar2022:03:00"dt lower="27Mar2022:02:00"dt /fillattrs=(color=lightblue)
legendlabel="Funkuhr_DE Zeitsprung mit Missing Values";
step y= E8601LX_Format x=Anzeige_Funkuhr_DE /group=timezone lineattrs=(thickness=3);
xaxis values=( "27Mar2022:01:00"dt "27Mar2022:01:59"dt "27Mar2022:03:00"dt "27Mar2022:04:00"dt )
valuesdisplay=( "27Mar2022:01" "27Mar2022:01:59" "27Mar2022:03" "27Mar2022:04" )
VALUESROTATE=DIAGONAL2 grid ;
yaxis values=("26Mar2022:24:00"dt to "27Mar2022:05:00"dt by 3600)
valuesdisplay=("26Mar2022:24+1" "27Mar2022:01+1" "27Mar2022:02+2" "27Mar2022:03+2" "27Mar2022:04+2" "27Mar2022:05+2")
grid TICKVALUEFORMAT=datetime15. label="UTC Time Format mit Offset nach ISO 8601";
keylegend / location=inside down=3;
run;
ods region;
proc report data=Fruhjahr(where=(mod(i,15) eq 0)) nowd;
column Rohwert_SAS datetime15_Format E8601LX_Format Offset TimeZone Anzeige_Funkuhr_DE;
define Rohwert_SAS / display;
define datetime15_Format / display;
define E8601LX_Format/display;
define Offset/display;
define Timezone/display;
define Anzeige_Funkuhr_DE/display;
compute Anzeige_Funkuhr_DE;
if Anzeige_Funkuhr_DE in ('27Mar22:01:45'dt, '27Mar22:03:00'dt) then call define(_col_,"style","style={background=lightblue}");
endcomp;
run;
ods Layout end;
options timezone='Europe/Berlin';
data Herbst;
Format Datetime15_Format Anzeige_Funkuhr_DE datetime15. Offset time2.;
Format E8601LX_Format E8601LX.;
Rohwert_SAS="30Oct2022:01:00"dt;
do i=1 to 215;
Rohwert_SAS =intnx('Minute', Rohwert_SAS,1);
Datetime15_Format= Rohwert_SAS;
E8601LX_Format= Rohwert_SAS;
Offset=TZONEOFF(Rohwert_SAS);
TimeZone=tzonename(Rohwert_SAS);
Anzeige_Funkuhr_DE= datetime15_Format+Offset-7200;
output;
end;
run;
Title "Coordinated Universal Time (UTC) Zeitformat gegenüber Funkuhr in Deutschland: Beispiel Zeitumstellung am 30 Oktober 2022, Timezone=Europe/Berlin";
ods layout gridded columns=2;
ods graphics on / height=335 width=550;
ods region;
proc sgplot data=Herbst;
title;footnote;
band y=E8601LX_Format upper="30Oct2022:03:00"dt lower="30Oct2022:02:00"dt /fillattrs=(color=lightblue) legendlabel="Funkuhr_DE: Zeitsprung mit Duplicates" ;
step y= E8601LX_Format x=Anzeige_Funkuhr_DE /group=timezone lineattrs=(thickness=3);
xaxis values=("30Oct2022:01:00"dt "30Oct2022:02:00"dt "30Oct2022:03:00"dt "30Oct2022:04:00"dt )
valuesdisplay=("30Oct2022:01" "30Oct2022:02" "30Oct2022:03" "30Oct2022:04" )
VALUESROTATE=DIAGONAL2 grid ;
yaxis values=("30Oct2022:01:00"dt to "30Oct2022:05:00"dt by 3600)
valuesdisplay=( "30Oct2022:01+1" "30Oct2022:02+2" "30Oct2022:03+2" "30Oct2022:04+2" "30Oct2022:05+2")
grid TICKVALUEFORMAT=datetime15. label="UTC Time Format mit Offset nach ISO 8601";
keylegend / location=inside down=3;
run;
ods region;
proc report data=Herbst(where=(mod(i,15) eq 0)) nowd;
column Rohwert_SAS datetime15_Format E8601LX_Format Offset TimeZone Anzeige_Funkuhr_DE;
define Rohwert_SAS / display;
define datetime15_Format / display;
define E8601LX_Format/display;
define Offset/display;
define Timezone/display;
define Anzeige_Funkuhr_DE/display;
compute Anzeige_Funkuhr_DE;
if Anzeige_Funkuhr_DE in ('30Oct22:02:00'dt, '30Oct22:02:15'dt, '30Oct22:02:30'dt , '30Oct22:02:45'dt, '30Oct22:03:00'dt) then call define(_col_,"style","style={background=lightblue}");
endcomp;
run;
ods Layout end;
ods html close;
Links auf weitere hilfreiche Informationen:
Dynamically Changing Time Zones and Daylight Savings on Time Series Data
Spring forward, fall back
Getting the time right across time zonesSAS Online Documentation: E8601LXw. Format
SAS Online Documentation: Specifying Time Zones
SAS Online Documentation: TZONENAME Function
SAS Online Documentation: TZONES2U Function
SAS Online Documentation: TZONEU2S Function