ABOUT Visual Basic Programmieren Programmierung Download Downloads Tips & Tricks Tipps & Tricks Know-How Praxis VB VBA Visual Basic for Applications VBS VBScript Scripting Windows ActiveX COM OLE API ComputerPC Microsoft Office Microsoft Office 97 Office 2000 Access Word Winword Excel Outlook Addins ASP Active Server Pages COMAddIns ActiveX-Controls OCX UserControl UserDocument Komponenten DLL EXE
Diese Seite wurde zuletzt aktualisiert am 22.04.2002

Diese Seite wurde zuletzt aktualisiert am 22.04.2002
Aktuell im ABOUT Visual Basic-MagazinGrundlagenwissen und TechnologienKnow How, Tipps und Tricks rund um Visual BasicActiveX-Komponenten, Controls, Klassen und mehr...AddIns für die Visual Basic-IDE und die VBA-IDEVBA-Programmierung in MS-Office und anderen AnwendungenScripting-Praxis für den Windows Scripting Host und das Scripting-ControlTools, Komponenten und Dienstleistungen des MarktesRessourcen für Programmierer (Bücher, Job-Börse)Dies&Das...

Themen und Stichwörter im ABOUT Visual Basic-Magazin
Code, Beispiele, Komponenten, Tools im Überblick, Shareware, Freeware
Ihre Service-Seite, Termine, Job-Börse
Melden Sie sich an, um in den vollen Genuss des ABOUT Visual Basic-Magazins zu kommen!
Informationen zum ABOUT Visual Basic-Magazin, Kontakt und Impressum

Zurück...

Feiertage, wie sie fallen

Zurück...


Anzeige

Gerrit Kuhlendahl mailto:GerritKulendahl_holidays@aboutvb.de

Feiertage soll man ja bekanntlich feiern, wie sie fallen. Und wenn Ihre Programme mitfeiern sollen, müssen diese natürlich erst einmal wissen, was und wann ein Feiertag ist. Mit einfachen Tabellen ist es nicht getan. Denn gemeinerweise sind liegen viele Feiertage wie etwa die Ostertage als auch diverse andere christliche Feiertage nicht auf einem festen Tag - sie sind so genannte "bewegliche" Feiertage. Erschwerend kommt noch hinzu, dass in der Bundesrepublik Deutschland die Feiertage regional unterschiedlich gelten. So sind die südlichen Bundesländer mit mehr Feiertagen gesegnet als die nördlichen.

Das Modul modHolidays hilft Ihnen bei der Ermittlung von Feiertagen. Dabei werden auch Feiertage in Österreich und in der Schweiz berücksichtigt, so sich diese von den deutschen Feiertagen unterscheiden. Außerdem wird auch die Besonderheit des "Tags der deutschen Einheit" berücksichtigt. Dieser wurde bis 1990 am 17. Juni gefeiert und wurde mit dem Vollzug der Einheit auf den 3. Oktober verlegt.

So unangenehm und kompliziert die Angelegenheit der beweglichen Feiertage auf den ersten Blick erscheinen mag, so simpel ist eigentlich deren Ermittlung: Die meisten der beweglichen Feiertage orientieren sich, am Ostersonntag. Es reicht also, diesen zu bestimmen und dann die entsprechenden Abstände dazu als Anzahl der Tage hinzuzählen oder abzuziehen. Lediglich der Buß- und Bettag führt ein Eigenleben: Er fällt immer auf den dritten Mittwoch im November. Die festen Feiertage kennen die Funktionen selbstverständlich auch.

Der Berechnung des Ostersonntags liegen im Großen und Ganzen die Mondphasen sowie einige weitere, nicht gerade triviale Gedanken zu Grunde, die seitens der christlichen Kirche noch mit einigen Ausnahmen gewürzt wurden. Aber auch hier haben wir Glück, dass sich andere längst vor uns hierüber den Kopf zerbrochen haben, so der berühmte Mathematiker Gauß. Von ihm stammt ein Algorithmus, der sich recht einfach implementieren lässt und für die Jahre von 1582 bis 2499 in der hier vorliegenden Form gültig ist.

Die Funktion EasterSunday implementiert diesen Algorithmus. Sie liefert ein Ergebnis vom Typ Date, das für das als Parameter übergebene Jahr den Ostersonntag liefert. Die Funktion löst einen Laufzeitfehler (HdErrInvalidYear) aus, wenn das übergebene Jahr nicht im gültigen Zeitraum liegt. Für solche mittelalterliche oder extrem zukünftige Feiertagsberechnungen werden Sie sich anderweitig umsehen müssen.

Public Const HdErrInvalidYear = 6

Public Function EasterSunday(ByVal TestYear As Integer) As Date
  Dim nN As Long
  Dim nM As Long
  Dim nA As Long
  Dim nB As Long
  Dim nC As Long
  Dim nD As Long
  Dim nE As Long
  Dim nDate As Date
  
  Select Case TestYear
    Case 1582 To 1699
      nM = 22
      nN = 2
    Case 1700 To 1799
      nM = 23
      nN = 3
    Case 1800 To 1899
      nM = 23
      nN = 4
    Case 1900 To 2099
      nM = 24
      nN = 5
    Case 2100 To 2199
      nM = 24
      nN = 6
    Case 2200 To 2299
      nM = 25
      nN = 0
    Case 2300 To 2399
      nM = 26
      nN = 1
    Case 2400 To 2499
      nM = 25
      nN = 1
    Case Else
      Err.Raise HdErrInvalidYear
  End Select
  nA = TestYear Mod 19
  nB = TestYear Mod 4
  nC = TestYear Mod 7
  nD = ((19 * nA) + nM) Mod 30
  nE = ((2 * nB) + (4 * nC) + (6 * nD) + nN) Mod 7
  If (22 + nD + nE) > 31 Then
    nDate = DateSerial(TestYear, 4, (nD + nE - 9))
  Else
    nDate = DateSerial(TestYear, 3, (22 + nD + nE))
  End If
  If Day(nDate) = 26 And Month(nDate) = 4 Then
    nDate = DateSerial(TestYear, 4, 19)
  End If
  If Day(nDate) = 25 And Month(nDate) = 4 Then
    If (nD = 28 And nA > 10) Then
      nDate = DateSerial(TestYear, 4, 18)
    End If
  End If
  EasterSunday = nDate
End Function

Für die weiteren Funktionen haben wir die Enumeration HolidayConstants definiert, die alle von den Routinen berücksichtigten Feiertage enthält. Die Werte sind dabei bitweise codiert, so dass die Einzelwerte über Oder-Operationen verknüpft werden können, um verschiedene Feiertage zu einzubeziehen. So können Sie auf einfache Art und Weise die Verwendung der Funktionen an den für eine Region gültigen Feiertagskalender anpassen.

Public Enum HolidayConstants
  KeineFeiertage = 0
  Neujahr = 1
  HlDreiKoenige = 2
  Rosenmontag = 4
  Karfreitag = 8
  OsterSo = 16
  OsterMo = 32
  ErsterMai = 64
  Himmelfahrt = 128
  PfingstSo = 256
  PfingstMo = 512
  Fronleichnam = 1024
  Bundesfeier = 2048
  AugsburgFrieden = 4096
  MariaHimmel = 8192
  DeutscheEinheit = 16384
  Nationalfeier = 32768
  Reformationstag = 65536
  Allerheiligen = 131072
  BussUndBet = 262144
  MariaEmpf = 524288
  Weihnacht1 = 1048576
  Weihnacht2 = 2097152
End Enum

Mit der Funktion Holiday ermitteln Sie das Datum eines beliebigen Feiertages in einem bestimmten Jahr. Hierzu bestimmt die Funktion den Ostersonntag des übergebenen Jahres und zählt den "Offset" des im zweiten Parameters angegebenen Feiertages hinzu, falls es sich um einen beweglichen Feiertag handelt. Bei festen Feiertagen wird der Wert direkt mittels der Funktion DateSerial gesetzt. Wurde ein ungültiger Wert als Holiday übergeben (ss muss sich hierbei direkt um einen Wert aus der Enumeration handeln - es darf kein verknüpfter Wert sein), wird der Laufzeitfehler HdErrInvalidHoliday ausgelöst.

Public Const HdErrInvalidHoliday = 5 

Public Function Holiday(ByVal TestYear As Integer, _
 ByVal Holidays As HolidayConstants) As Date

  Dim nEasterDate As Date
  Dim nDaysNovember As Integer
  
  Select Case TestYear
    Case 1582 To 2499
    Case Else
      Err.Raise HdErrInvalidYear
  End Select
  nEasterDate = EasterSunday(TestYear)
  Select Case Holidays
    Case Neujahr
      Holiday = DateSerial(TestYear, 1, 1)
    Case HlDreiKoenige
      Holiday = DateSerial(TestYear, 1, 6)
    Case Rosenmontag
      Holiday = DateAdd("d", -48, nEasterDate)
    Case Karfreitag
      Holiday = DateAdd("d", -2, nEasterDate)
    Case OsterSo
      Holiday = nEasterDate
    Case OsterMo
      Holiday = DateAdd("d", 1, nEasterDate)
    Case ErsterMai
      Holiday = DateSerial(TestYear, 5, 1)
    Case Himmelfahrt
      Holiday = DateAdd("d", 39, nEasterDate)
    Case PfingstSo
      Holiday = DateAdd("d", 49, nEasterDate)
    Case PfingstMo
      Holiday = DateAdd("d", 50, nEasterDate)
    Case Fronleichnam
      Holiday = DateAdd("d", 60, nEasterDate)
    Case Bundesfeier
      Holiday = DateSerial(TestYear, 8, 1)
    Case AugsburgFrieden
      Holiday = DateSerial(TestYear, 8, 8)
    Case MariaHimmel
      Holiday = DateSerial(TestYear, 8, 15)
    Case DeutscheEinheit
      Select Case TestYear
        Case 1954 To 1989
          Holiday = DateSerial(TestYear, 6, 17)
        Case Is > 1989
          Holiday = DateSerial(TestYear, 10, 3)
        Case Else
          Err.Raise HdErrInvalidYear
      End Select
    Case Nationalfeier
      Holiday = DateSerial(TestYear, 10, 26)
    Case Reformationstag
      Holiday = DateSerial(TestYear, 12, 31)
    Case Allerheiligen
      Holiday = DateSerial(TestYear, 11, 1)
    Case BussUndBet
      For nDaysNovember = 1 To 7
        nEasterDate = DateSerial(TestYear, 11, nDaysNovember)
        If Weekday(nEasterDate) = 4 Then
          Holiday = DateAdd("d", 14, nEasterDate)
          Exit Function
        End If
      Next nDaysNovember
    Case MariaEmpf
      Holiday = DateSerial(TestYear, 12, 6)
    Case Weihnacht1
      Holiday = DateSerial(TestYear, 12, 25)
    Case Weihnacht2
      Holiday = DateSerial(TestYear, 12, 26)
    Case Else
      Err.Raise HdErrInvalidHoliday
  End Select
End Function

Mit der Funktion IsHoliday prüfen Sie, ob es sich bei einem übergebenen Datum um einen Feiertag handelt. Damit die Funktion richtig arbeiten kann, übergeben Sie im zweiten Parameter einen Long-Wert, dessen einzelne Bits (aus der oben erwähnten Enumeration zusammengesetzt) die entsprechenden zulässigen bzw. als möglich gewünschten Feiertage symbolisieren. Auch damit Sie sich diese Bits und Ihre Bedeutung nicht merken müssen, haben wir die Enumeration definiert. Insbesondere hier erleichtert sie Ihnen dank Intellisense die Auswahl und Zusammenstellung. Wenn es sich um einen Feiertag handelt, gibt die Funktion True, anderenfalls False zurück.

Public Function IsHoliday(ByVal TestDate As Date, _
 ByVal Holidays As HolidayConstants) As Boolean

  Dim nTestHoliday As Long
  Dim nTest As Long
  
  TestDate = CLng(CDbl(TestDate))
  Select Case Year(TestDate)
    Case 1582 To 2499
    Case Else
      Err.Raise HdErrInvalidYear
  End Select
  For nTestHoliday = 1 To 21
    nTest = 2 ^ nTestHoliday
    If (Holidays And nTest) = nTest Then
      If Holiday(Year(TestDate), nTest) = TestDate Then
        IsHoliday = True
        Exit Function
      End If
    End If
  Next 'nTestHoliday
End Function

Die Funktion HolidaysOfYear gibt als Ergebnis eine Collection mit allen Feiertagen eines übergebenen Jahres zurück. Auch hier müssen Sie natürlich angeben, welche Feiertage sie berücksichtigt wissen möchten. Sie können auf die einzelnen Werte der Collection entweder über den Index zugreifen oder über den entsprechenden Schlüssel (Key). Den Schlüssel bilden Sie einfach, indem Sie die jeweilige Konstante aus der HolidayConstants-Enumeration mit CStr in einen String konvertieren (eine Zahl wird von einer Collection nicht als Index, sondern als String-Schlüssel interpretiert, wenn sie ausdrücklich in einen String konvertiert übergeben wird).

Public Function HolidaysOfYear(ByVal TestYear As Integer, _
 ByVal Holidays As HolidayConstants) As Collection

  Dim nTestHoliday As Long
  Dim nTest As Long

  Select Case TestYear
    Case 1582 To 2499
    Case Else
      Err.Raise HdErrInvalidYear
  End Select
  Set HolidaysOfYear = New Collection
  With HolidaysOfYear
    For nTestHoliday = 1 To 21
      nTest = 2 ^ nTestHoliday
      If (Holidays And nTest) = nTest Then
        HolidaysOfYear.Add Holiday(TestYear, nTest), _
         CStr(nTestHoliday)
      End If
    Next 'nTestHoliday
  End With
End Function

Falls Sie nun noch die solch wichtige Tage wie heilig Abend und Sylvester vermissen: Nun, erstens sind das keine gesetzlichen Feiertage. Und zweitens können Sie diese doch ganz einfach ermitteln, indem Sie vom 1. Weihnachtsfeiertag bzw. von Neujahr einen Tag abziehen.


Modul modHolidays (modHolidays.zip - ca. 2 KB)


Artikel
Zum Download-Bereich dieses Artikel
Mail an den Autor dieses Artikels

KnowHow
Zur KnowHow-Übersicht

KnowHow-Themen
Themen - Allgemeines
Themen - Entwicklungsumgebung (VB-IDE)
Themen - Forms
Themen - Steuerelemente (Controls)
Themen - Grafik
Themen - Dateien
Themen - UserControls
Themen - Einsteiger-Tipps
Themen - Wussten Sie...?

Übersicht nach Titeln in alphabetischer Reihenfolge
Übersicht nach Erscheinungsdatum

Schnellsuche




Zum Seitenanfang

Copyright © 1999 - 2017 Harald M. Genauck, ip-pro gmbh  /  Impressum

Zum Seitenanfang

Zurück...

Zurück...

Download Internet Explorer