Beim Aufbau eines Data Warehouse gehören Datumsdimensionen zum Standard. Im Regelfall sollen hierbei auch die Feiertage mit einfließen – eine einfache Anforderung, so lange es um ein feststehendes Datum geht. Will man indes bewegliche Feiertage berechnen, gestaltet sich diese Aufgabe ungleich komplexer. Zwar besteht die Möglichkeit, die betreffenden Daten anhand von statistischen Tabellen – wie man sie beispielsweise auf schulferien.org findet – manuell einzupflegen. Für moderne DWH-Lösungen mit hohem Automatisierungsgrad darf dies jedoch keine Option sein.
Bewegliche Feiertage berechnen mit Gauß-Algorithmus
Eine generische Lösung bietet der Gauß-Algorithmus zur Berechnung des Ostersonntags. Liegt dieser erst einmal vor, lassen sich auch weitere bewegliche Feiertage berechnen. Microsoft stellt in diesem Kontext eine Implementierung für Visual Basic zur Verfügung. Jedoch lässt sich nicht in jedem Projekt ein selbstgeschriebener Code als CLR im SQL Server installieren. Daher ist es sinnvoll, diesen Code zunächst in die TSQL-Syntax zu überführen:
-
CREATE FUNCTION [dbo].[FuncOstersonntag] (@Jahr AS BIGINT)
-
returns DATETIME
-
AS
-
BEGIN
-
— Declare the return variable here
-
— Osterfunktion nach Carl Friedrich Gauß (1800). Rückgabewert
-
— ist das Datum des Ostersonntags im angegebenen
-
— Jahr. Gültigkeitsbereich: 1583 – 8702 (auf das
-
— Auslösen von Laufzeitfehlern bei Unter- oder Überschreitung
-
— dieses Gültigkeitsbereichs wird hier absichtlich verzichtet).
-
DECLARE @a AS BIGINT
-
DECLARE @b AS BIGINT
-
DECLARE @c AS BIGINT
-
DECLARE @d AS BIGINT
-
DECLARE @e AS BIGINT
-
DECLARE @f AS BIGINT
-
DECLARE @date AS CHAR(8)
-
-
– Die „magische“ Gauss–Formel anwenden: SET @a = @Jahr % 19 SET @b = @Jahr / 100 SET @c = ( 8 * @b + 13 ) / 25 – 2 SET @d = @b – ( @Jahr / 400 ) – 2 SET @e = ( 19 * ( @Jahr % 19 ) + ( ( 15 – @c + @d ) % 30 ) ) % 30 IF @e = 28 BEGIN IF @a > 10 BEGIN SET @e = 27 END END ELSE BEGIN IF @e = 29 BEGIN SET @e = 28 END END SET @f = ( @d + 6 * @e + 2 * ( @Jahr % 4 ) + 4 * ( @Jahr % 7 ) + 6 ) % 7 — Rückgabewert als Datum bereitstellen SET @date = CONVERT(CHAR(8), @Jahr * 10000 + 101, 112) SET @date = CONVERT(CHAR(8), Dateadd(mm, 2, @date), 112) SET @date = CONVERT(CHAR(8), Dateadd(dd, @e + @f + 21, @date), 112) RETURN Cast(@date AS DATETIME) END
Nun muss man nur noch feste und bewegliche Feiertage berechnen. Im Folgenden eine Funktion, die die Feiertage für ein Jahr generiert:
-
CREATE FUNCTION [dbo].[Gettageinklfeiertage] (@Jahr VARCHAR(4))
-
returns @TageinklFeiertag TABLE (
-
datum DATE NOT NULL,
-
istfeiertag INT NOT NULL,
-
feiertag VARCHAR(20) NOT NULL,
-
wochentag VARCHAR(20) NOT NULL )
-
AS
-
BEGIN
-
DECLARE @Datum AS DATE
-
DECLARE @hdatum AS DATE
-
DECLARE @Feiertagname AS VARCHAR(20)
-
DECLARE @istftag AS INT
-
DECLARE @Ostern AS DATE
-
SELECT @ostern = [dbo].[Funcostersonntag] (@jahr) SET @Datum =Cast (@Jahr * 10000 + 100 + 1 AS VARCHAR(10)) SET @hdatum = CONVERT (VARCHAR (10), ( Cast (@Jahr AS INT) + 1 ) * 10000 + 100 + 1) WHILE @Datum < @hdatum BEGIN SET @Feiertagname =“ SET @istftag = 0 IF Day(@Datum) = 1 AND Month (@Datum) = 1 BEGIN SET @Feiertagname = ‚Neujahr‘ SET @istftag = 1 END IF Day(@Datum) = 1 AND Month (@Datum) = 5 BEGIN SET @Feiertagname = ‚Tag der Arbeit‘ SET @istftag = 1 END IF Day(@Datum) = 3 AND Month (@Datum) = 10 BEGIN SET @Feiertagname = ‚Tag der Deutschen Einheit‘ SET @istftag = 1 END IF Day(@Datum) = 1 AND Month (@Datum) = 11 BEGIN SET @Feiertagname = ‚Allerheiligen‘ SET @istftag = 1 END IF Day(@Datum) = 25 AND Month (@Datum) = 12 BEGIN SET @Feiertagname = ‚1.Weihnachstag‘ SET @istftag = 1 END IF Day(@Datum) = 26 AND Month (@Datum) = 12 BEGIN SET @Feiertagname = ‚2.Weihnachstag‘ SET @istftag = 1 END IF @Datum = Dateadd(d, –2, @Ostern) BEGIN SET @Feiertagname = ‚Karfreitag‘ SET @istftag = 1 END IF @Datum = @Ostern BEGIN SET @Feiertagname = ‚Ostersonntag‘ SET @istftag = 1 END IF @Datum = Dateadd(d, 1, @Ostern) BEGIN SET @Feiertagname = ‚Ostermontag‘ SET @istftag = 1 END IF @Datum = Dateadd(d, 39, @Ostern) BEGIN SET @Feiertagname = ‚Christi Himmelfahrt‘ SET @istftag = 1 END IF @Datum = Dateadd(d, 50, @Ostern) BEGIN SET @Feiertagname = ‚Pfingstmontag‘ SET @istftag = 1 END IF @Datum = Dateadd(d, 60, @Ostern) BEGIN SET @Feiertagname = ‚Fronleichnahm‘ SET @istftag = 1 END
-
INSERT INTO @TageinklFeiertag
-
VALUES (@Datum,
-
@istftag,
-
@Feiertagname,
-
Datename(dw, @Datum))
-
SET @Datum= Dateadd(d, 1, @Datum) END RETURN END
Die resultierende Tabelle kann natürlich durch weitere, erforderliche Datumsinformationen ergänzt werden. Zudem sollte die Tabelle zumindest für Ostersonntag bis ins Jahr 8702 die richtigen Ergebnisse liefern. Aktuell sind nur die Feiertage aus Nordrhein-Westfalen implementiert. Dabei ist zu beachten, dass in 2017 aufgrund des 500. Jahrestages der Reformation auch der 31. Oktober hinzu kommt. Wie sich unschwer am Code erkennen lässt, ist dieser Sachverhalt ebenfalls noch nicht berücksichtigt.
Kommentare (0)