SAS SP-Integration

Dieses Dokument wurde erstellt von Dr. Rolf Becker, SP Integration GmbH.
Bestimmungsmethoden für die Generierung einer
Zeitdimension
In den Projekten von SP Integration kam von Kundenseite immer wieder der Wunsch nach einer
einfach zu handhabenden Berechnungsmethodik zur Bestimmung einer Zeitdimension als Bestandteil
des Kunden-Data-Warehouse auf. Die Dimensionstabelle sollte einerseits das Datum auflösen (Jahr,
Monat, Tag, Wochentag, Quartal, Kalenderwoche usw.) und somit alle wesentlichen Bestandteile für
die Bildung von Hierarchien insbesondere für OLAP Cubes bereitstellen (mit Visual Analytics lässt sich
dieser Teil inzwischen mit wenigen Klicks generieren). Andererseits sollte sie feste und bewegliche
Feiertage, Arbeitstage (in Monat und Jahr) und ggf. ein vom Kalenderjahr abweichendes Fiskaljahr
(abweichende Jahres- und Monatswerte) beinhalten. So ist der im Anhang beigefügte SAS Code
entstanden, der in Projekten zumeist als Generated Transformation für DI-Studio-Jobs den Kunden
bereitgestellt wird.
Die beweglichen Feiertage lassen sich vom Datum des Ostersonntags ableiten. Letzterer lässt sich
über den von LICHENBERG (1997) modifizierten Ansatz von Gauss bestimmen. Dieser Ansatz wird
von der Physikalisch-Technischen Bundesanstalt (PTB) verwendet, die vom Gesetzgeber den Auftrag
erhalten hat, „die gesetzliche Zeit darzustellen und zu verbreiten“ (JURIS 2015). In Ihrem OnlineAngebot beschreibt die PTB (2015) den Lichtenberg‘schen Ansatz ausführlich, der sich in
nachfolgendem SAS Code widerspiegelt:
var_k = int(Jahr / 100);
var_m = 15 + int((3 * var_k + 3) / 4) - int((8 * var_k + 13) / 25);
var_s = 2 - int((3 * var_k + 3) / 4);
var_a = Jahr - (19 * int(Jahr / 19));
var_d = (19 * var_a + var_m)- (30 * int((19 * var_a + var_m) / 30));
var_r = int(var_d / 29) + (int(var_d / 28) - int(var_d / 29)) * int(var_a / 11);
var_og = 21 + var_d - var_r;
var_sz = 7 - (Jahr + int(Jahr / 4) + var_s) - (7 * int((Jahr + int(Jahr / 4) + var_s)/ 7));
var_test = (7 * int((var_og - var_sz)/ 7));
var_oe = 7 - (var_og - var_sz) + (7 * int((var_og - var_sz)/ 7));
var_os = var_og + var_oe;
if var_os <= 31 then Ostersonntag = mdy(3, var_os, Jahr);
else Ostersonntag = mdy(4, (var_os - 31), Jahr);
Die beweglichen Feiertage lassen sich wie folgt vom Datum des Ostersonntags ableiten:
 Karfreitag: Ostersonntag – 2 Tage
 Ostermontag: Ostersonntag + 1 Tag
 Christi Himmelfahrt: Ostersonntag + 39 Tage
 Pfingstsonntag: Ostersonntag + 49 Tage
 Pfingstmontag: Ostersonntag + 50 Tage
 Fronleichnam: Ostersonntag + 60 Tage
Unter Einbeziehung der beweglichen und festen Feiertage sowie des Wochentags lässt sich dann leicht
bestimmen, ob ein Datum innerhalb der Zeitdimension einen Arbeitstag repräsentiert oder nicht.
Innerhalb des beigefügten SAS Codes werden die Anzahl der Arbeitstage als Year-to-Date
(Arbeitstag_im_Jahr) bzw. Month-to-Date-Werte (Arbeitstag_im_Monat) in der Zeitdimension abgelegt.
Literatur
H. Lichtenberg (1997): Zur Interpretation der Gaußschen Osterformel und ihrer Ausnahmeregeln,
Historia Mathematica 24, 441 - 444.
JURIS (2015): Gesetz über die Einheiten im Messwesen und die Zeitbestimmung (Einheiten- und
Zeitgesetz - EinhZeitG), Onlineangebot.
PTB (2015): Wann ist Ostern; http://www.ptb.de/cms/fachabteilungen/abt4/fb-44/ag-441/darstellungder-gesetzlichen-zeit/wann-ist-ostern.html.
Der gesamter Code
/*
==============================================================================
=== */
/* erstellt durch:
Dr. Rolf Becker
*/
/*
Principal Consultant
*/
/*
SP Integration GmbH
*/
/*
Otto-Volger-Str. 5a
*/
/*
65843 Sulzbach (Taunus)
*/
/*
+49 177 3164480
*/
/*
[email protected]
*/
/* erstellt am:
12.05.2015
*/
/* zuletzt gaendert am: 12.05.2015
*/
/* Beschreibung:
Skript zum Erstellen der Zeitdimension
*/
/*
- beweglicher Feiertage
*/
/*
- Arbeitstage je Monat und Jahr
*/
/*
- Fiskaljahr (optional)
*/
/*
*/
/*
==============================================================================
=== */
/* Aenderungsdatum / Aenderung
*/
/* durch wen
*/
/*
*/
/*
==============================================================================
=== */
%let _OUTPUT=DimTime;
/*Zieldatei*/
%let u_StartDatum=01JAN1970; /*kleinstes Datum der Zeit-Dimension*/
%let u_EndDatum=31DEC2030; /*größtes Datum der Zeit-Dimension*/
%let u_MonatFiskaljahr=11; /*Ende des Fiskaljahrs (Monat)*/
proc format;
value fWochentag 1 = 'Sonntag'
2 = 'Montag'
3 = 'Dienstag'
4 = 'Mittwoch'
5 = 'Donnerstag'
6 = 'Freitag'
7 = 'Samstag'
;
run;
proc format;
value fMonat 1 = 'Januar'
2 = 'Februar'
3 = 'März'
4 = 'April'
5 = 'Mai'
6 = 'Juni'
7 = 'Juli'
8 = 'August'
9 = 'September'
10 = 'Oktober'
11 = 'November'
12 = 'Dezember'
;
run;
data &_OUTPUT(label='Zeitdimension' sortedby=Datum);
keep Datum DateKey Wochentag_Nr Wochentag Monat_Nr Monat_Jahr Monat KW_Nr KW_Jahr Jahr
Quartal Fiskal_Jahr Fiskal_Monat_Nr
Fiskal_Quartal Tag_im_Monat Tag_im_Jahr Arbeitstag_im_Monat Arbeitstag_im_Jahr Feiertag_Flag
Feiertag;
length Datum DateKey Wochentag_Nr 8 Wochentag $10 Monat_Nr 8 Monat_Jahr Monat $9 KW_Nr 8
KW_Jahr $9 Jahr 8 Quartal $6
Fiskal_Jahr 8 Fiskal_Monat_Nr 8 Fiskal_Quartal $6 Tag_im_Monat Tag_im_Jahr
Arbeitstag_im_Monat 8
Arbeitstag_im_Jahr Feiertag_Flag 8 Feiertag $30;
format Datum ddmmyyp10.;
do Datum="&u_StartDatum"d to "&u_EndDatum"d;
DateKey = year(Datum) * 10000 + month(Datum) * 100 + day(Datum);
Wochentag_Nr = weekday(Datum);
Wochentag = put(Wochentag_Nr, fWochentag10.);
Jahr = year(Datum);
Monat_Nr = month(Datum);
Monat_Jahr = put(Jahr,4.) !! '/' !! put(month(Datum),Z2.);
Monat = put(Monat_Nr, fMonat9.);
Quartal = put(Jahr,4.) !! 'Q' !! put(qtr(Datum),1.);
KW_Nr = week(Datum, 'V');
KW_Jahr = put(Jahr,4.) !! '/' !! put(week(Datum,'V'),Z2.);
if Monat_Nr <= &u_MonatFiskaljahr then do;
Fiskal_Jahr = Year(Datum);
Fiskal_Monat_Nr = month(Datum)+1;
end;
else do;
Fiskal_Jahr = year(Datum)+1;
Fiskal_Monat_Nr = 1;
end;
Fiskal_Quartal = compress(put(Fiskal_Jahr, 4.) !! 'Q' !! put(ceil(Fiskal_Monat_Nr/3),1.));
Tag_im_Monat = day(Datum);
if Monat_Nr = 1 and Tag_im_Monat = 1 then Tag_im_Jahr = 1;
else Tag_im_Jahr = Tag_im_Jahr + 1;
/* bewegliche Feiertage - Berechnung des Ostermsonntags nach Gauss, modifiziert von Lichtenberg
*/
/* H. Lichtenberg (1997): Zur Interpretation der Gaußschen Osterformel und ihrer Ausnahmeregeln,
Historia Mathematica 24, 441 - 444. */
/* http://www.ptb.de/cms/fachabteilungen/abt4/fb-44/ag-441/darstellung-der-gesetzlichen-zeit/wannist-ostern.html */
var_k = int(Jahr / 100);
var_m = 15 + int((3 * var_k + 3) / 4) - int((8 * var_k + 13) / 25);
var_s = 2 - int((3 * var_k + 3) / 4);
var_a = Jahr - (19 * int(Jahr / 19));
var_d = (19 * var_a + var_m)- (30 * int((19 * var_a + var_m) / 30));
var_r = int(var_d / 29) + (int(var_d / 28) - int(var_d / 29)) * int(var_a / 11);
var_og = 21 + var_d - var_r;
var_sz = 7 - (Jahr + int(Jahr / 4) + var_s) - (7 * int((Jahr + int(Jahr / 4) + var_s)/ 7));
var_test = (7 * int((var_og - var_sz)/ 7));
var_oe = 7 - (var_og - var_sz) + (7 * int((var_og - var_sz)/ 7));
var_os = var_og + var_oe;
if var_os <= 31 then Ostersonntag = mdy(3, var_os, Jahr);
else Ostersonntag = mdy(4, (var_os - 31), Jahr);
/*bewegliche Feiertage (Hessen)*/
if Datum = Ostersonntag then do;
Feiertag_Flag = 1;
Feiertag = 'Ostersonntag';
end;
else if Datum = Ostersonntag - 2 then do;
Feiertag_Flag = 1;
Feiertag = 'Kafreitag';
end;
else if Datum = Ostersonntag + 1 then do;
Feiertag_Flag = 1;
Feiertag = 'Ostermontag';
end;
else if Datum = Ostersonntag + 39 then do;
Feiertag_Flag = 1;
Feiertag = 'Christi Himmelfahrt';
end;
else if Datum = Ostersonntag + 49 then do;
Feiertag_Flag = 1;
Feiertag = 'Pfingstsonntag';
end;
else if Datum = Ostersonntag + 50 then do;
Feiertag_Flag = 1;
Feiertag = 'Pfingstmontag';
end;
else if Datum = Ostersonntag + 60 then do;
Feiertag_Flag = 1;
Feiertag = 'Fronleichnahm';
end;
/* feste Feiertage (Hessen) */
else if Monat_Nr = 1 and Tag_im_Monat = 1 then do;
Feiertag_Flag = 1;
Feiertag = 'Neujahr';
end;
else if Monat_Nr = 5 and Tag_im_Monat = 1 then do;
Feiertag_Flag = 1;
Feiertag = 'Maifeiertag';
end;
else if Monat_Nr = 10 and Tag_im_Monat = 3 then do;
Feiertag_Flag = 1;
Feiertag = 'Tag der deutschen Einheit';
end;
else if Monat_Nr = 12 and Tag_im_Monat = 25 then do;
Feiertag_Flag = 1;
Feiertag = '1. Weihnachtsfeiertag';
end;
else if Monat_Nr = 12 and Tag_im_Monat = 26 then do;
Feiertag_Flag = 1;
Feiertag = '2. Weihnachtsfeiertag';
end;
else do;
Feiertag_Flag = 0;
Feiertag = '';
end;
/* Arbeitstage */
if Monat_Nr = 1 and Tag_im_Monat = 1 then do;
if Wochentag_Nr not in (1,7) and Feiertag_Flag = 0 then do;
Arbeitstag_im_Jahr = 1;
Arbeitstag_im_Monat = 1;
end;
else do;
Arbeitstag_im_Jahr = 0;
Arbeitstag_im_Monat = 0;
end;
end;
else if Tag_im_Monat = 1 then do;
if Wochentag_Nr not in (1,7) and Feiertag_Flag = 0 then do;
Arbeitstag_im_Monat = 1;
Arbeitstag_im_Jahr = Arbeitstag_im_Jahr + 1;
end;
else Arbeitstag_im_Monat = 0;
end;
else do;
if Wochentag_Nr not in (1,7) and Feiertag_Flag = 0 then do;
Arbeitstag_im_Monat = Arbeitstag_im_Monat + 1;
Arbeitstag_im_Jahr = Arbeitstag_im_Jahr + 1;
end;
end;
Output;
end;
run;
SAS INSTITUTE GMBH
IN DER NECKARHELLE 162 69118 HEIDELBERG
Phone: +49 6221 415-0 Fax: +49 6221 415-101 www.sas.com/deutschland
Eine Tochtergesellschaft von SAS Institute Inc., SAS Circle, Box 8000, Cary, NC 27512-8000, USA. Sitz der Gesellschaft Heidelberg,
Registergericht Mannheim, HRB 332269, Geschäftsführer Wolf Lichtenstein, Finanzamt Heidelberg, Steuer-Nr. 32497/83950.