vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
Erstellen von dynamischen Kontextmen?s - wann immer Sie sie brauchen!  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2024
 
zurück
Rubrik: Datum/Zeit und Timer · Datums- und Zeitfunktionen   |   VB-Versionen: VB617.01.05
Bewegliche Feiertage und Arbeitstage eines Monats

Mit diesen Funktionen lässt sich prüfen, ob ein bestimmtes Datum ein Arbeitstag oder Feiertag ist. Weiterhin lassen sich auch noch die Anzahl Arbeitstage eines Monats ermitteln.

Autor:   Hermann RöttgerBewertung:     [ Jetzt bewerten ]Views:  46.663 
www.direct-solutions-software.comSystem:  Win9x, WinNT, Win2k, WinXP, Win7, Win8, Win10, Win11 Beispielprojekt auf CD 

Wer sich schon einmal mit Datumsberechnungen beschäftigen musste (und wer musste das noch nicht...), wird sich sicherlich darüber geärgert haben, das VB keine Funktion bietet, mit der sich bewegliche Feiertage einfach (und zuverlässig...) berechnen lassen. Bedenkt man jedoch, wie viele unterschiedliche bewegliche Feiertage es international gibt, wird rasch klar, warum sich Microsoft diesbezüglich zurückgehalten hat...

Das Problem jedoch bleibt: Wer z.B. "mal eben" berechnen will, wie viele Arbeitstage ein bestimmter Monat oder Zeitraum hat bzw. wissen muss, ob ein bestimmter Wochentag vielleicht gleichzeitig ein Feiertag ist, wird relativ schnell verzweifeln und mit festen Werten arbeiten, die einfach vom Kalender abgelesen werden.

Ist es z.B. noch relativ einfach, die Anzahl der Tage eines Monats - unter Berücksichtigung von Schaltjahren -nach dem altbekannten "Fingerknöchelsystem" festzusetzen, hat uns leider niemand eine ähnliche Eselsbrücke beigebracht, wenn es um die Berechnung von beweglichen Feiertagen geht...

Dabei ist es relativ einfach: Alle beweglichen deutschen Feiertage lassen sich sehr einfach anhand des Ostersonntags berechnen. So errechnet sich der Pfingstmontag z.B. per "Ostersonntag + 50" oder Frohnleichnahm per "Ostersonntag + 60".

Wie aber ermittelt man nun den Ostersonntag?

Ich musste seinerzeit ziemlich lange suchen, bis ich herausfand, auf welchen seltsamen Pfaden die Kalenderfuzzies auf dieses Datum kommen... Ich will euch nicht weiter mit Details langweilen, aber die Berechnung ist deshalb so komplex, weil sie nicht anhand des Sonnen- sondern des Mondkalenders durchgeführt wird. Die bekannte Abweichung zwischen diesen beiden Zeitsystemen führt übrigens auch zu den mitunter enormen Datumsdifferenzen zwischen den Ostersonntagen verschiedener Jahre.

Ok, genug der Theorie:
Hier nun zunächst die Funktion, mit der sich der Ostersonntag eines beliebigen Jahres berechnen lässt. An die Funktion wird ein Jahr im Format JJJJ übergeben (also zB "2004"). Der Rückgabewert ist das Datum des Ostersonntags:

' Berechnung des Ostersonntags
Public Function Ostern(X As Integer) As Date
  Dim K As Integer
  Dim M As Integer
  Dim S As Integer
  Dim D As Integer
  Dim R As Integer
  Dim A As Integer
  Dim OG As Integer
  Dim SZ As Integer
  Dim OE As Integer
  Dim OSI As Integer
  Dim OS1 As Double
  Dim OS2 As String
 
  K = Int(X / 100)
  M = 15 + Int((3 * K + 3) / 4) - Int((8 * K + 13) / 25)
  S = 2 - Int((3 * K + 3) / 4)
  A = X Mod 19
  D = (19 * A + M) Mod 30
  R = Int(D / 29) + (Int(D / 28) - Int(D / 29)) * Int(A / 11)
  OG = 21 + D - R
  SZ = 7 - (X + Int(X / 4) + S) Mod 7
  OE = 7 - (OG - SZ) Mod 7
  OSI = ((OG + OE) - 1)
  OS2 = "01.03." & X
  OS2 = CDate(OS2)
  OS1 = CDate(OS2)
  OS1 = CDbl(OS1)
  OS1 = OS1 + OSI
  OS1 = CDate(OS1)
 
  Ostern = OS1
End Function

Jetzt versteht ihr sicherlich, warum ich die Funktion nicht im Detail erkläre

Was noch fehlt, sind z.B. Funktionen, die anhand des Ostersonntages die anderen beweglichen Feiertage berechnen. Eine solche Funktion könnte so aussehen:

' Ermitteln, ob Datum "x" ein Arbeitstag ist
' (Sa/So zählt nicht als Arbeitstag!)
' 
' Aufruf per:
' Rückgabewert = Arbeitstag(ÜbergabeDatum)
' 
' Ist der Rückgabewert = 0, handelt es sich um einen Samstag, Sonntag oder/und Feiertag
' Ist der Rückgabewert = 1, handelt es sich um einen normalen Arbeitstag
Public Function Arbeitstag(X As Date) As Integer
  Dim Feiertage(12) As Date
  Dim Feiertag As String
  Dim Jahr As Integer
  Dim SaSo As Integer
  Dim i As Long
 
  ' Jahr aus übergebenem Datum ermitteln
  Jahr = CInt(Format(X, "yyyy"))
 
  ' Wochentag ermitteln
  SaSo = CInt(Weekday(X))
 
  ' Arbeitstag = 1 / normaler Werktag
  ' Arbeitstag = 0 / Samstag, Sonntag und/oder Feiertag
  Arbeitstag = 1
 
  ' Ist der Tag ein Samstag oder Sonntag ?
  If (SaSo = 1 Or SaSo = 7) Then
    ' Ja, kein Arbeitstag
    Arbeitstag = 0
  Else
    ' Nein - ist der Tag ein beweglicher oder fester gesetzlicher Feiertag ?
 
    ' Bewegliche Feiertage ermitteln
    ' Karfreitag
    Feiertage(1) = (Ostern(Jahr)) - 2
    ' Ostermontag
    Feiertage(2) = (Ostern(Jahr)) + 1
    ' Pfingstmontag
    Feiertage(3) = (Ostern(Jahr)) + 50
    ' Himmelfahrt
    Feiertage(4) = (Ostern(Jahr)) + 39
    ' Frohnleichnam
    Feiertage(5) = (Ostern(Jahr)) + 60
 
    ' Feste Feiertage ermitteln
    ' Neujahr
    Feiertage(6) = CDate("01.01." & Jahr)
    ' 1.Mai
    Feiertage(7) = CDate("01.05." & Jahr)
    ' Tag der deutschen Einheit
    Feiertage(8) = CDate("03.10." & Jahr)
    ' Allerheiligen
    Feiertage(9) = CDate("01.11." & Jahr)
    ' 1. Weihnachtstag
    Feiertage(10) = CDate("25.12." & Jahr)
    ' 2.Weihnachtstag
    Feiertage(11) = CDate("26.12." & Jahr)
 
    ' Stimmt das übergebene Datum mit einem der Feiertage überein ?
    For i = 1 To 11
      If X = Feiertage(i) Then
        ' Ja, kein Arbeitstag
        Arbeitstag = 0
        Exit For
      End If
    Next i
  End If
End Function

Jetzt wird es z.B. auch möglich, die "wahre" Anzahl der Arbeitstage eines beliebigen Monats zu errechnen. Hierzu brauchen wir noch eine weitere Funktion, welche die beiden vorangegangenen nutzt:

' Ermitteln der Arbeitstage eines Monats
' Übergeben wird ein Datum, z.B. 01.05.2005
Public Function ArbeitsTage(X As Date) As Integer
  Dim Monat As Integer
  Dim Tage As Integer
  Dim AT As Integer
  Dim Start As Date
  Dim Ende As Date
  Dim i As Long
 
  ' Tage des Monats ermitteln
  Monat = CInt(Format(X, "mm"))
  Tage = Choose(Monat, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
  If Monat = 2 Then
    ' Speziallfall: Februar (auf Schaltjahr prüfen)
    Tage = Day(DateAdd("d", -1, X))
  End If
 
  ' Start und Enddatum des Monats ermitteln
  Start = CDate("01." & Format(Monat, "00") & "." & Format(X, "yyyy"))
  Ende = CDate(Start) + (Tage - 1)
 
  ' Arbeitstage ermitteln
  For i = Start To Ende
    AT = AT + Arbeitstag(CDate(i))
  Next i
 
  ArbeitsTage = AT
End Function

Wie werden die Funktionen nun genutzt?

Das Datum von Ostern berechnet man nun z.B. per:

Dim Ostersonntag as Date
Ostersonntag = Ostern(2004)

Prüfen ob ein bestimmter einzelner Tag ein Arbeitstag oder kein Arbeitstag (Sa, So oder Feiertag) ist:

Dim Datum As Date
Datum = "16.01.2005"
If Arbeitstag(Datum) = 0 then
  ' Datum Ist ein Feiertag
Else
  ' Datum ist kein Feiertag
End If

Und schließlich noch das Berechnen der Arbeitstage eines Monats (Datum ist ein Datum im Format dd.mm.yyyy):

Dim Datum As Date
Datum = "01.01.2005"
MsgBox Arbeitstage(Datum)

So, ich hoffe, dass euch diese Routinen bei zukünftigen Projekten helfen werden. Anwendungsgebiete (z.B. auch als Formel in Excel!!) und Erweiterungsmöglichkeiten gibt es sicherlich genug.
 

Dieser Tipp wurde bereits 46.663 mal aufgerufen.

Voriger Tipp   |   Zufälliger Tipp   |   Nächster Tipp

Über diesen Tipp im Forum diskutieren
Haben Sie Fragen oder Anregungen zu diesem Tipp, können Sie gerne mit anderen darüber in unserem Forum diskutieren.

Aktuelle Diskussion anzeigen (4 Beiträge)

nach obenzurück


Anzeige

Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Tipps & Tricks finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6
(einschl. Beispielprojekt!)

Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
- nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
- Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
 
   

Druckansicht Druckansicht Copyright ©2000-2024 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel