- Offizieller Beitrag
Auf Anregung durch Xeno habe ich auf der Basis meiner (leicht veränderten) Feiertagsfunktion die Funktion _GetWorkingDaysInRange( ) erstellt.
Damit lassen sich für einen Datumsbereich (der auch mehrere Jahre umfassen kann - ist dann etwas lahm) die entsprechende Anzahl an Arbeitstagen ermitteln.
Es können entweder ausschließlich Bundesweit gesetzliche Feiertage oder die Feiertage eines bestimmten Bundeslandes (inkl. der Bundesweit gesetzlichen) berücksichtigt werden. Für diesen Parameter kann ein Index oder das Bundeseinheitliche Landeskürzel übergeben werden.
Die Anzahl der Wochenarbeitstage kann von 5 (Standard) bis 7 gesetzt werden. Heiligabend und Silvester gehen mit 0,5 Tagen in die Rechnung ein.
Edit 26.08.2015
Ich habe den Code in Teilen der aktuellen Syntax angepaßt (Verwendung ternärer Operatoren) und einen echten Bug gefixed. Der Parameter für die Anzahl der Arbeitstage pro Woche wurde gar nicht in die Berechnungsfunktion weitergeleitet, sondern nur mit 5 (Mo-Fr) gerechnet.
Hier nun die korrekte Version v0.2
;-- TIME_STAMP 2015-08-26 11:51:04 v 0.2
#include-once
#include <Math.au3>
#include <Date.au3>
#include <Array.au3>
;===============================================================================
; Function Name: _GetWorkingDaysInRange
; Description:: Ermittelt die Anzahl an Arbeitstagen in einem übergebenen Datumsbereich, auch spezifisch nach Bundesland,
; auch Jahresübergreifend;
; Heiligabend und Silvester werden mit 0,5 Arbeitstagen berechnet;
; Anzahl der Wochenarbeitstage variabel (5-7)
; Parameter(s): $sFromDate Startdatum
; $sToDate Enddatum
; $vFederalState Index oder Kürzel des BundesLandes
; 0 BG nur Bundesweit gesetzlich
; 1 SH Schleswig-Holstein
; 2 HH Freie und Hansestadt Hamburg
; 3 NI Niedersachsen
; 4 HB Freie Hansestadt Bremen
; 5 NW Nordrhein-Westfalen
; 6 HE Hessen
; 7 RP Rheinland-Pfalz
; 8 BW Baden-Württemberg
; 9 BY Bayern
; 10 SL Saarland
; 11 BE Berlin
; 12 BB Brandenburg
; 13 MV Mecklenburg-Vorpommern
; 14 SN Freistaat Sachsen|Sachsen
; 15 ST Sachsen-Anhalt
; 16 TH Thüringen
; $iCountWorkDays Anzahl Arbeitstage pro Woche (5=Mo-Fr Standard; 6=Mo-Sa; 7=Mo-So)
; Requirement(s): Funktionen: _Feiertage(), __IsWorkingDay()
; Return Value(s): Anzahl der Arbeitstage
; Author(s): BugFix
;===============================================================================
Func _GetWorkingDaysInRange($sFromDate, $sToDate, $vFederalState=0, $iCountWorkDays=5)
Local $aSplitFrom = StringSplit($sFromDate, '.', 2)
Local $aSplitTo = StringSplit($sToDate, '.', 2)
Local $aYears[1] = [$aSplitFrom[2]] ; für jahresübergreifende Daten
If $aSplitTo[2] <> $aSplitFrom[2] Then
ReDim $aYears[$aSplitTo[2]-$aSplitFrom[2]+1]
For $i = 1 To UBound($aYears) -1
$aYears[$i] = $aYears[$i-1] +1
Next
EndIf
Local $aHolidays, $iWorkingDayCounter = 0, $n = 0, $sTmpDate
Switch UBound($aYears)
Case 1 ; Datumswerte in einem Jahr
$aHolidays = _Feiertage($aYears[0],$vFederalState, 0, 0, 1)
Do
$sTmpDate = _DateAdd('D', $n, $aSplitFrom[2] & '/' & $aSplitFrom[1] & '/' & $aSplitFrom[0])
$iWorkingDayCounter += __IsWorkingDay($aHolidays, $sTmpDate, $iCountWorkDays)
$n += 1
Until $aSplitTo[2] & '/' & $aSplitTo[1] & '/' & $aSplitTo[0] = $sTmpDate
Case 2 ; Datumswerte in zwei Jahren
$aHolidays = _Feiertage($aYears[0],$vFederalState, 0, 0, 1)
Do
$sTmpDate = _DateAdd('D', $n, $aSplitFrom[2] & '/' & $aSplitFrom[1] & '/' & $aSplitFrom[0])
$iWorkingDayCounter += __IsWorkingDay($aHolidays, $sTmpDate, $iCountWorkDays)
$n += 1
If $aSplitFrom[2] & '/12/31' = $sTmpDate Then $aHolidays = _Feiertage($aYears[1],$vFederalState, 0, 0, 1)
Until $aSplitTo[2] & '/' & $aSplitTo[1] & '/' & $aSplitTo[0] = $sTmpDate
Case Else ; Datumswerte über mehr als 2 Jahre
Local $tmpYear, $index = 0, $sDateEnd = $aSplitTo[2] & '/' & $aSplitTo[1] & '/' & $aSplitTo[0]
$aHolidays = _Feiertage($aYears[$index],$vFederalState, 0, 0, 1)
Do
$sTmpDate = _DateAdd('D', $n, $aSplitFrom[2] & '/' & $aSplitFrom[1] & '/' & $aSplitFrom[0])
$iWorkingDayCounter += __IsWorkingDay($aHolidays, $sTmpDate, $iCountWorkDays)
$n += 1
$tmpYear = StringLeft($sTmpDate, 4)
If $tmpYear & '/12/31' = $sTmpDate And $tmpYear & '/12/31' <> $sDateEnd Then
$index += 1
$aHolidays = _Feiertage($aYears[$index],$vFederalState, 0, 0, 1)
EndIf
Until $sDateEnd = $sTmpDate
EndSwitch
Return $iWorkingDayCounter
EndFunc ;==>_GetWorkingDaysInRange
Func __IsWorkingDay(ByRef $aHolidays, $sDate, $iCountWorkDays)
; 5 Werktage, Sa/So frei; 6 Werktage, So frei; 7 Werktage, ./. frei
Local $sFreeDay = $iCountWorkDays < 6 ? '6 7' : ($iCountWorkDays = 6 ? '7' : 'N')
Local $aSplitDate = StringSplit($sDate, '/', 2)
Local $iWeekday = _DateToDayOfWeekISO($aSplitDate[0], $aSplitDate[1], $aSplitDate[2])
If @error Then Return 0
If StringInStr($sFreeDay, $iWeekday) Then Return 0 ; ist Sa./So. = kein WorkingDay
Local $index = _ArraySearch($aHolidays, $sDate, 0, 0, 1)
If $index = -1 Then Return 1 ; nicht in Feiertagen (u. kein Sa./So.) = WorkingDay
Local $sDay = StringRight($sDate, 5)
If $sDay = '12/24' Or $sDay = '12/31' Then Return 0.5 ; Halber Feiertag (24./31. Dez.)
Return 0 ; in Feiertagen = kein WorkingDay
EndFunc ;==>__IsWorkingDay
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Funktion _Feiertage($Jahr)
;
; gibt die Feiertage des übergebenen Jahres
; als sortiertes Array[TT.MM.JJJJ od. JJJJ/MM/TT][Feiertag][Geltungsbereich][opt. Wochentag] zurück
; Geltungsbereich Leerstring - kein offizieller Feiertag
; BG - Bundesweit Gesetzlich
; Regionalkennzeichen: BB-Brandenburg BE-Berlin BW-Baden-Württemberg BY-Bayern
; HB-Bremen HE-Hessen HH-Hamburg MV-Mecklenburg-Vorpommern
; NI-Niedersachsen NW-Nordrhein-Westfalen RP-Rheinland-Pfalz
; SH-Schleswig-Holstein SL-Saarland SN-Sachsen
; ST-Sachsen-Anhalt TH-Thüringen
; $vBundesland -1 alle Feiertage mit Geltungsbereich (Bundesländer), (Standard)
; 0 BG nur Bundesweit gesetzlich
;
; Bundesland (inkl. BG)
; 1 SH Schleswig-Holstein
; 2 HH Freie und Hansestadt Hamburg
; 3 NI Niedersachsen
; 4 HB Freie Hansestadt Bremen
; 5 NW Nordrhein-Westfalen
; 6 HE Hessen
; 7 RP Rheinland-Pfalz
; 8 BW Baden-Württemberg
; 9 BY Bayern
; 10 SL Saarland
; 11 BE Berlin
; 12 BB Brandenburg
; 13 MV Mecklenburg-Vorpommern
; 14 SN Freistaat Sachsen|Sachsen
; 15 ST Sachsen-Anhalt
; 16 TH Thüringen
; $DateTyp 1 - Datum als TT.MM.JJJJ (Standard)
; 0 - Datum als JJJJ/MM/TT
; $wDay 0 - Rückabe Wochentag numerisch 1-7 / Sonntag-Samstag
; 1 - Rückgabe Wochentag ($array[n][3])
; $sort 0 - gegliedert fix/variabel (Standard), innerhalb sortiert
; 1 - komplett sortiert
; Autor BugFix (bugfix@autoit.de)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func _Feiertage($year, $vBundesland=-1, $DateTyp=1, $wDay=0, $sort=0)
Local $4AdvDat, $3AdvDat, $2AdvDat, $1AdvDat, $TotSoDat, $BuBDat, $MutterDat, $ErnteDat, $tmp
Local $HDays[33][4], $a, $b, $c, $d, $e, $H1, $H2, $N, $M, $Tempyear, $RestJahr
Local $aWDays[8] = [7,'Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Sonnabend']
Local $aBuLand[17] = ['BG','SH','HH','NI','HB','NW','HE','RP','BW','BY','SL','BE','BB','MV','SN','ST','TH']
If IsString($vBundesland) Then $vBundesland = _ArraySearch($aBuLand, $vBundesland)
;fixe Feiertage
$HDays[0][0] = $year & "/01/01\Neujahr\BG"
$HDays[1][0] = $year & "/01/06\Heilige Drei Könige\BW BY ST"
$HDays[2][0] = $year & "/02/14\Valentinstag\"
$HDays[3][0] = $year & "/05/01\Maifeiertag\BG"
$HDays[4][0] = $year & "/08/15\Mariä Himmelfahrt\BY SL"
$HDays[5][0] = $year & "/10/03\Tag der Deutschen Einheit\BG"
$HDays[6][0] = $year & "/10/31\Reformationstag\BB MV SN ST TH"
$HDays[7][0] = $year & "/11/01\Allerheiligen\BW BY NW RP SL"
$HDays[8][0] = $year & "/12/24\Heiligabend\BG"
$HDays[9][0] = $year & "/12/25\1. Weihnachtsfeiertag\BG"
$HDays[10][0] = $year & "/12/26\2. Weihnachtsfeiertag\BG"
$HDays[11][0] = $year & "/12/31\Silvester\BG"
;variable Feiertage
$a = Mod($year, 19)
$b = Mod($year, 4)
$c = Mod($year, 7)
$H1 = Int($year / 100)
$H2 = Int($year / 400)
$N = 4 + $H1 - $H2
$M = 15 + $H1 - $H2 - Floor (Int((8 * $H1 + 13) / 25))
$d = Mod((19 * $a + $M), 30)
$e = Mod((2 * $b + 4 * $c + 6 * $d + $N), 7)
$EasterDay = ($d + $e = 35) ? 50 : (($d = 28 And $e = 6 And $a > 10) ? 49 : 22 + $d + $e)
$EasterMonth = '03'
If $EasterDay > 31 Then
$EasterDay -= 31
$EasterMonth = '04'
EndIf
$EasterDay = StringRight("0" & $EasterDay, 2)
If $year < 1900 Then ; Datumsoperationen nur mgl. wenn > 1900 , Jahr wird konvertiert
$RestJahr = StringRight("0" & Mod($year, 100), 2)
$Tempyear = _DateIsLeapYear($year) ? 20 & $RestJahr : 19 & $RestJahr
$EasterDate = $Tempyear & "/" & $EasterMonth & "/" & $EasterDay
Else
$EasterDate = $year & "/" & $EasterMonth & "/" & $EasterDay
EndIf
$WFastDate = _DateAdd( 'd', -52, $EasterDate)
$RosDat = _DateAdd( 'd', -48, $EasterDate)
$FastDat = _DateAdd( 'd', -47, $EasterDate)
$AschDat = _DateAdd( 'd', -46, $EasterDate)
$GrDoDat = _DateAdd( 'd', -3, $EasterDate)
$KarDat = _DateAdd( 'd', -2, $EasterDate)
$OSaDat = _DateAdd( 'd', -1, $EasterDate)
$OSoDat = $EasterDate
$OMoDat = _DateAdd( 'd', 1, $EasterDate)
$HiFaDat = _DateAdd( 'd', 39, $EasterDate)
$PfSoDat = _DateAdd( 'd', 49, $EasterDate)
$PfMoDat = _DateAdd( 'd', 50, $EasterDate)
$FroDat = _DateAdd( 'd', 60, $EasterDate)
; Ermitteln nicht von Ostern abhängiger, veränderlicher Feiertage
; Muttertag = 2. Sonntag im Mai ABER wenn Pfingsten = 2.Sonntag im Mai dann ist Muttertag am 1. Sonntag
; Der 2. Sonntag kann nur zw. dem 8. u. 14.5. liegen
For $maitag = 8 To 14
If _DateToDayOfWeek($year, 5, $maitag) = 1 Then
$maitag = StringRight("0" & $maitag, 2)
$MutterDat = $year & "/05/" & $maitag
If $MutterDat = $PfSoDat Then
$MutterDat = _DateAdd( 'd', -7, $year & "/05/" & $maitag)
EndIf
ExitLoop
EndIf
Next
; Erntedankfest 1. Sonntag im Oktober (zw. 1. u. 7.10.)
For $oktobertag = 1 To 7
If _DateToDayOfWeek($year, 10, $oktobertag) = 1 Then
$ErnteDat = $year & "/10/" & StringRight("0" & $oktobertag, 2)
ExitLoop
EndIf
Next
; 4.Advent = Sonntag vor 25.12. (zw. 18. u. 24.12.)
For $deztag = 18 To 24
If _DateToDayOfWeek($year, 12, $deztag) = 1 Then
$4AdvDat = $year & "/12/" & $deztag
$3AdvDat = _DateAdd( 'd', -7, $4AdvDat)
$2AdvDat = _DateAdd( 'd', -14, $4AdvDat)
$1AdvDat = _DateAdd( 'd', -21, $4AdvDat)
$TotSoDat = _DateAdd( 'd', -28, $4AdvDat)
$BuBDat = _DateAdd( 'd', -32, $4AdvDat)
ExitLoop
EndIf
Next
$HDays[12][0] = $WFastDate & "\Weiberfastnacht\"
$HDays[13][0] = $RosDat & "\Rosenmontag\"
$HDays[14][0] = $FastDat & "\Fastnacht\"
$HDays[15][0] = $AschDat & "\Aschermittwoch\"
$HDays[16][0] = $GrDoDat & "\Gründonnerstag\"
$HDays[17][0] = $KarDat & "\Karfreitag\BG"
$HDays[18][0] = $OSaDat & "\Ostersamstag\"
$HDays[19][0] = $OSoDat & "\Ostersonntag\"
$HDays[20][0] = $OMoDat & "\Ostermontag\BG"
$HDays[21][0] = $HiFaDat & "\Christi Himmelfahrt\BG"
$HDays[22][0] = $PfSoDat & "\Pfingstsonntag\"
$HDays[23][0] = $PfMoDat & "\Pfingstmontag\BG"
$HDays[24][0] = $MutterDat & "\Muttertag\"
$HDays[25][0] = $FroDat & "\Fronleichnam\BW BY HE NW RP SL SN TH"
$HDays[26][0] = $ErnteDat & "\Erntedankfest\"
$HDays[27][0] = $BuBDat & "\Buß- und Bettag\SN"
$HDays[28][0] = $TotSoDat & "\Totensonntag\"
$HDays[29][0] = $1AdvDat & "\1. Advent\"
$HDays[30][0] = $2AdvDat & "\2. Advent\"
$HDays[31][0] = $3AdvDat & "\3. Advent\"
$HDays[32][0] = $4AdvDat & "\4. Advent\"
If $sort Then
_ArraySort($HDays)
Else
_ArraySort($HDays, 0, 0, 11)
_ArraySort($HDays, 0, 12)
EndIf
For $i = 0 To 32
$tmp = StringSplit($HDays[$i][0], "\", 2)
If $DateTyp Then ; Datum konvertieren zu TT.MM.JJJJ
$HDays[$i][0] = StringRight($tmp[0],2) & "." & StringMid($tmp[0],6,2) & "." & StringLeft($tmp[0],4)
Else
$HDays[$i][0] = $tmp[0]
EndIf
$HDays[$i][1] = $tmp[1]
$HDays[$i][2] = $tmp[2]
If $wDay = 1 Then
$HDays[$i][3] = $aWDays[_DateToDayOfWeek(StringLeft($tmp[0],4), StringMid($tmp[0],6,2), StringRight($tmp[0],2))]
Else
$HDays[$i][3] = _DateToDayOfWeek(StringLeft($tmp[0],4), StringMid($tmp[0],6,2), StringRight($tmp[0],2))
EndIf
Next
If $vBundesland > -1 Then
Local $aTmp[1][4]
For $i = 0 To 32
If StringInStr($HDays[$i][2], $aBuLand[$vBundesland], 1) Or StringInStr($HDays[$i][2], 'BG', 1) Then
If $aTmp[UBound($aTmp)-1][0] <> '' Then ReDim $aTmp[UBound($aTmp)+1][4]
$aTmp[UBound($aTmp)-1][0] = $HDays[$i][0]
$aTmp[UBound($aTmp)-1][1] = $HDays[$i][1]
$aTmp[UBound($aTmp)-1][2] = $HDays[$i][2]
$aTmp[UBound($aTmp)-1][3] = $HDays[$i][3]
EndIf
Next
Return $aTmp
EndIf
Return $HDays
EndFunc ;==>_Feiertage
Alles anzeigen