Get Bi-Weekly Paydays And Major US Holidays With PowerShell
Example PowerShell code to generate paydays and holidays with or without full calendar. The Holiday function could be shorter and more elegant, but it works for my needs.
<# Basic functions to get bi-weekly pay and major holidays. May need alterations on Windows or Mac. I am on Linux. Author: C. Nichols #> function Get-Paydays () { param ( [int]$FirstPayMonth = 1, [int]$FirstPayDay = 12, [int]$Year = 2024 ) $WeekNum = @{ Sunday=0; Monday=1; Tuesday=2; Wednesday=3; Thursday=4; Friday=5; Saturday=6 } if (-not($Year)) { $CurrentYear = (Get-Date).Year } else { $CurrentYear = $Year } $FirstPayOfYear = Get-Date -Year $CurrentYear -Month $FirstPayMonth -Day $FirstPayDay $EndOfYear = Get-Date -Year $CurrentYear -Month 12 -Day 31 $CurrentDate = $FirstPayOfYear $Paydays = New-Object -TypeName "System.Collections.ArrayList" While ($CurrentDate -lt $EndOfYear) { If ($CurrentDate.DayOfWeek -eq 'Friday') { $MonthName = (Get-Culture).DateTimeFormat.GetMonthName($CurrentDate.Month) $DayName = $CurrentDate.DayOfWeek.ToString() $PayDate = [PsCustomObject]@{ MonthName=$MonthName; Month=$CurrentDate.Month; WeekIndex=$WeekNum[$DayName]; DayName=$DayName; Day=$CurrentDate.Day; Year=$CurrentYear; Desc="payday" } $Paydays += $PayDate } $CurrentDate = $CurrentDate.AddDays(14) } return $Paydays } function Get-Holidays() { PARAM ( [int]$Year=2024 ) $WeekNum = @{ Sunday=0; Monday=1; Tuesday=2; Wednesday=3; Thursday=4; Friday=5; Saturday=6 } $FIXED_HOLIDAYS = @{12=@{25="Christmas Day"}; 1=@{1="New Year's Day"}; 6=@{19="Juneteenth"}; 7=@{4="Independence Day"}; 11=@{11="Veteran's Day"} } $HOLIDAYS = @{1=@{3="Martin Luther King, Jr.Birthday"}; # 3rd Monday in Jan. 2=@{3="President's Day"}; # 3rd Monday in Feb. (President's Day) #5="memorial"; # Last Monday in May. Handled separately. 9=@{1="Labor Day"}; # 1st Monday in Sept. 10=@{2="Columbus Day"}; # 2nd Monday in Oct. 11=@{4="Thanksgiving"} # 4th Thursday in Nov. } $HolidayCalendar = @{} $Calendar = @{} $Rows = New-Object -TypeName "System.Collections.ArrayList" if (-not($Year)) { $Year = (Get-Date).Year } # Link month name to day names for year. ForEach ($Month in 1..12) { $DaysInMonth = [datetime]::DaysInMonth($Year,$Month) ForEach ($Day in 1..$DaysInMonth) { $DateObject = Get-Date -Year $Year -Month $Month -Day $Day $DayName = $DateObject.DayOfWeek if (-not($Calendar.ContainsKey($Month))) { $Calendar[$Month] = @{} } $Calendar[$Month][$Day] = $DayName } } # Get a increamental count of each weekday in month. $MonthKeys = $Calendar.Keys ForEach ($MonthKey in $MonthKeys | Sort-Object) { $DayHash = $Calendar[$MonthKey] $MonCount = 0 $MemArray = @() $DayKeys = $DayHash.Keys ForEach ($DayKey in $DayKeys | Sort-Object) { $MonthDays = $DayHash[$DayKey] $Holiday = "" if ($FIXED_HOLIDAYS.ContainsKey($MonthKey)) { $Holiday = $FIXED_HOLIDAYS[$MonthKey][$DayKey] } if ($MonthDays -eq "Monday") { $MonCount += 1 if ($HOLIDAYS.ContainsKey($MonthKey)) { if ($HOLIDAYS[$MonthKey].ContainsKey($MonCount)) { $Holiday = $HOLIDAYS[$MonthKey][$MonCount] } } } if ($MonthKey -eq 5) { if ($MonthDays -eq "Monday") { $MemArray += $DayKey } } if (-not($HolidayCalendar.ContainsKey($MonthKey))) { $HolidayCalendar[$MonthKey] = @{} } if (-not($HolidayCalendar[$MonthKey].ContainsKey($DayKey))) { $HolidayCalendar[$MonthKey][$DayKey] = "" } $HolidayCalendar[$MonthKey][$DayKey] = $Holiday } if ($MemArray[-1]) { $Memday = $MemArray[-1] $HolidayCalendar[5][$Memday] = "Memorial Day" } } $MthKeys = $HolidayCalendar.Keys ForEach ($mk in $MthKeys | Sort-Object) { $MonthName = (Get-Culture).DateTimeFormat.GetMonthName($mk) #Write-Host $MonthName $DayKeys = $HolidayCalendar[$mk].Keys ForEach ($dk in $DayKeys | Sort-Object) { $DateObject = Get-Date -Year $Year -Month $mk -Day $dk $DayName = $DateObject.DayOfWeek.ToString() $HolidayDesc = $null if ($HolidayCalendar[$mk][$dk]) { $HolidayDesc = $HolidayCalendar[$mk][$dk] } if ($DayName -eq "Saturday") { $DateObject = $DateObject.AddDays(-1) $DayName = $DateObject.DayOfWeek.ToString() } if ($DayName -eq "Sunday") { $DateObject = $DateObject.AddDays(1) $DayName = $DateObject.DayOfWeek.ToString() } $Columns = [PsCustomObject]@{ MonthName=$MonthName; Month=$mk; WeekIndex=$WeekNum[$DayName]; DayName=$DayName; Day=$dk; Year=$Year; Desc=$HolidayDesc } $Rows += $Columns } } return $Rows } <# Main :: Merge and offset clashes. #> $WeekNum = @{ Sunday=0; Monday=1; Tuesday=2; Wednesday=3; Thursday=4; Friday=5; Saturday=6 } $MergedRows = @() $DateHash = @{} # Ge major holidays. $MyHolidays = Get-Holidays #-Year 2026 $MyPaydays = Get-Paydays #-Year 2026 -FirstPayMonth 1 -FirstPayDay 9 ForEach ($p in $MyPaydays) { $Pdate = Get-Date -Year $p.Year -Month $p.Month -Day $p.Day if (-not($DateHash.ContainsKey($Pdate.Date))) { $DateHash[$Pdate.Date] = $p } } ForEach ($h in $MyHolidays) { if ($h.Desc) { $Hdate = Get-Date -Year $h.Year -Month $h.Month -Day $h.Day if (-not($DateHash.ContainsKey($Hdate.Date))) { $DateHash[$Hdate.Date] = $h } else { $Pdate = Get-Date -Year $DateHash[$Hdate.Date].Year -Month $DateHash[$Hdate.Date].Month -Day $DateHash[$Hdate.Date].Day $Pdate = $Pdate.AddDays(-1) $MonthName = (Get-Culture).DateTimeFormat.GetMonthName($Pdate.Month) $DayName = $Pdate.DayOfWeek.ToString() $Column = [PsCustomObject]@{ MonthName=$MonthName; Month=$Pdate.Month; WeekIndex=$WeekNum[$DayName]; DayName=$DayName; Day=$Pdate.Day; Year=$Pdate.Year; Desc="payday" } $DateHash[$Hdate.Date] = $h $DateHash[$Pdate.Date] = $Column } } } # create report. $ReportRows = @() $DateKeys = $DateHash.Keys ForEach ($mdate in $DateKeys | Sort-Object) { Write-Host $DateHash[$mdate] $ReportRows += $DateHash[$mdate] } # Save as CSV. #$ReportRows | Export-Csv -Path "~/PrCal.csv" -NoTypeInformation <# OUTPUT @{MonthName=January; Month=1; WeekIndex=1; DayName=Monday; Day=1; Year=2024; Desc=New Year's Day} @{MonthName=January; Month=1; WeekIndex=5; DayName=Friday; Day=12; Year=2024; Desc=payday} @{MonthName=January; Month=1; WeekIndex=1; DayName=Monday; Day=15; Year=2024; Desc=Martin Luther King, Jr.Birthday} @{MonthName=January; Month=1; WeekIndex=5; DayName=Friday; Day=26; Year=2024; Desc=payday} @{MonthName=February; Month=2; WeekIndex=5; DayName=Friday; Day=9; Year=2024; Desc=payday} @{MonthName=February; Month=2; WeekIndex=1; DayName=Monday; Day=19; Year=2024; Desc=President's Day} @{MonthName=February; Month=2; WeekIndex=5; DayName=Friday; Day=23; Year=2024; Desc=payday} @{MonthName=March; Month=3; WeekIndex=5; DayName=Friday; Day=8; Year=2024; Desc=payday} @{MonthName=March; Month=3; WeekIndex=5; DayName=Friday; Day=22; Year=2024; Desc=payday} @{MonthName=April; Month=4; WeekIndex=5; DayName=Friday; Day=5; Year=2024; Desc=payday} @{MonthName=April; Month=4; WeekIndex=5; DayName=Friday; Day=19; Year=2024; Desc=payday} @{MonthName=May; Month=5; WeekIndex=5; DayName=Friday; Day=3; Year=2024; Desc=payday} @{MonthName=May; Month=5; WeekIndex=5; DayName=Friday; Day=17; Year=2024; Desc=payday} @{MonthName=May; Month=5; WeekIndex=1; DayName=Monday; Day=27; Year=2024; Desc=Memorial Day} @{MonthName=May; Month=5; WeekIndex=5; DayName=Friday; Day=31; Year=2024; Desc=payday} @{MonthName=June; Month=6; WeekIndex=5; DayName=Friday; Day=14; Year=2024; Desc=payday} @{MonthName=June; Month=6; WeekIndex=3; DayName=Wednesday; Day=19; Year=2024; Desc=Juneteenth} @{MonthName=June; Month=6; WeekIndex=5; DayName=Friday; Day=28; Year=2024; Desc=payday} @{MonthName=July; Month=7; WeekIndex=4; DayName=Thursday; Day=4; Year=2024; Desc=Independence Day} @{MonthName=July; Month=7; WeekIndex=5; DayName=Friday; Day=12; Year=2024; Desc=payday} @{MonthName=July; Month=7; WeekIndex=5; DayName=Friday; Day=26; Year=2024; Desc=payday} @{MonthName=August; Month=8; WeekIndex=5; DayName=Friday; Day=9; Year=2024; Desc=payday} @{MonthName=August; Month=8; WeekIndex=5; DayName=Friday; Day=23; Year=2024; Desc=payday} @{MonthName=September; Month=9; WeekIndex=1; DayName=Monday; Day=2; Year=2024; Desc=Labor Day} @{MonthName=September; Month=9; WeekIndex=5; DayName=Friday; Day=6; Year=2024; Desc=payday} @{MonthName=September; Month=9; WeekIndex=5; DayName=Friday; Day=20; Year=2024; Desc=payday} @{MonthName=October; Month=10; WeekIndex=5; DayName=Friday; Day=4; Year=2024; Desc=payday} @{MonthName=October; Month=10; WeekIndex=1; DayName=Monday; Day=14; Year=2024; Desc=Columbus Day} @{MonthName=October; Month=10; WeekIndex=5; DayName=Friday; Day=18; Year=2024; Desc=payday} @{MonthName=November; Month=11; WeekIndex=5; DayName=Friday; Day=1; Year=2024; Desc=payday} @{MonthName=November; Month=11; WeekIndex=1; DayName=Monday; Day=11; Year=2024; Desc=Veteran's Day} @{MonthName=November; Month=11; WeekIndex=5; DayName=Friday; Day=15; Year=2024; Desc=payday} @{MonthName=November; Month=11; WeekIndex=1; DayName=Monday; Day=25; Year=2024; Desc=Thanksgiving} @{MonthName=November; Month=11; WeekIndex=5; DayName=Friday; Day=29; Year=2024; Desc=payday} @{MonthName=December; Month=12; WeekIndex=5; DayName=Friday; Day=13; Year=2024; Desc=payday} @{MonthName=December; Month=12; WeekIndex=3; DayName=Wednesday; Day=25; Year=2024; Desc=Christmas Day} @{MonthName=December; Month=12; WeekIndex=5; DayName=Friday; Day=27; Year=2024; Desc=payday} #>