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.
PowerShell
x
320
320
1
<#
2
Basic functions to get bi-weekly pay and major holidays.
3
May need alterations on Windows or Mac. I am on Linux.
4
Author: C. Nichols
5
#>
6
function Get-Paydays () {
7
param (
8
[int]$FirstPayMonth = 1,
9
[int]$FirstPayDay = 12,
10
[int]$Year = 2024
11
)
12
13
$WeekNum = @{
14
Sunday=0;
15
Monday=1;
16
Tuesday=2;
17
Wednesday=3;
18
Thursday=4;
19
Friday=5;
20
Saturday=6
21
}
22
23
if (-not($Year)) {
24
$CurrentYear = (Get-Date).Year
25
} else {
26
$CurrentYear = $Year
27
}
28
29
$FirstPayOfYear = Get-Date -Year $CurrentYear -Month $FirstPayMonth -Day $FirstPayDay
30
$EndOfYear = Get-Date -Year $CurrentYear -Month 12 -Day 31
31
32
$CurrentDate = $FirstPayOfYear
33
$Paydays = New-Object -TypeName "System.Collections.ArrayList"
34
While ($CurrentDate -lt $EndOfYear)
35
{
36
37
If ($CurrentDate.DayOfWeek -eq 'Friday') {
38
39
$MonthName = (Get-Culture).DateTimeFormat.GetMonthName($CurrentDate.Month)
40
$DayName = $CurrentDate.DayOfWeek.ToString()
41
42
$PayDate = [PsCustomObject]@{
43
MonthName=$MonthName;
44
Month=$CurrentDate.Month;
45
WeekIndex=$WeekNum[$DayName];
46
DayName=$DayName;
47
Day=$CurrentDate.Day;
48
Year=$CurrentYear;
49
Desc="payday"
50
}
51
52
$Paydays += $PayDate
53
}
54
55
$CurrentDate = $CurrentDate.AddDays(14)
56
57
}
58
59
return $Paydays
60
}
61
62
function Get-Holidays() {
63
PARAM (
64
[int]$Year=2024
65
)
66
67
$WeekNum = @{
68
Sunday=0;
69
Monday=1;
70
Tuesday=2;
71
Wednesday=3;
72
Thursday=4;
73
Friday=5;
74
Saturday=6
75
}
76
77
$FIXED_HOLIDAYS = @{12=@{25="Christmas Day"};
78
1=@{1="New Year's Day"};
79
6=@{19="Juneteenth"};
80
7=@{4="Independence Day"};
81
11=@{11="Veteran's Day"}
82
}
83
84
$HOLIDAYS = @{1=@{3="Martin Luther King, Jr.Birthday"}; # 3rd Monday in Jan.
85
2=@{3="President's Day"}; # 3rd Monday in Feb. (President's Day)
86
#5="memorial"; # Last Monday in May. Handled separately.
87
9=@{1="Labor Day"}; # 1st Monday in Sept.
88
10=@{2="Columbus Day"}; # 2nd Monday in Oct.
89
11=@{4="Thanksgiving"} # 4th Thursday in Nov.
90
}
91
92
$HolidayCalendar = @{}
93
$Calendar = @{}
94
$Rows = New-Object -TypeName "System.Collections.ArrayList"
95
96
if (-not($Year)) {
97
$Year = (Get-Date).Year
98
}
99
100
# Link month name to day names for year.
101
ForEach ($Month in 1..12) {
102
103
$DaysInMonth = [datetime]::DaysInMonth($Year,$Month)
104
105
ForEach ($Day in 1..$DaysInMonth) {
106
107
$DateObject = Get-Date -Year $Year -Month $Month -Day $Day
108
$DayName = $DateObject.DayOfWeek
109
110
if (-not($Calendar.ContainsKey($Month))) {
111
$Calendar[$Month] = @{}
112
}
113
114
$Calendar[$Month][$Day] = $DayName
115
116
}
117
}
118
119
# Get a increamental count of each weekday in month.
120
$MonthKeys = $Calendar.Keys
121
ForEach ($MonthKey in $MonthKeys | Sort-Object) {
122
123
$DayHash = $Calendar[$MonthKey]
124
$MonCount = 0
125
$MemArray = @()
126
127
$DayKeys = $DayHash.Keys
128
ForEach ($DayKey in $DayKeys | Sort-Object) {
129
130
$MonthDays = $DayHash[$DayKey]
131
$Holiday = ""
132
133
if ($FIXED_HOLIDAYS.ContainsKey($MonthKey)) {
134
135
$Holiday = $FIXED_HOLIDAYS[$MonthKey][$DayKey]
136
137
}
138
139
if ($MonthDays -eq "Monday") {
140
$MonCount += 1
141
if ($HOLIDAYS.ContainsKey($MonthKey)) {
142
if ($HOLIDAYS[$MonthKey].ContainsKey($MonCount)) {
143
144
$Holiday = $HOLIDAYS[$MonthKey][$MonCount]
145
146
}
147
}
148
}
149
150
if ($MonthKey -eq 5) {
151
152
if ($MonthDays -eq "Monday") {
153
$MemArray += $DayKey
154
}
155
}
156
157
if (-not($HolidayCalendar.ContainsKey($MonthKey))) {
158
$HolidayCalendar[$MonthKey] = @{}
159
}
160
161
if (-not($HolidayCalendar[$MonthKey].ContainsKey($DayKey))) {
162
$HolidayCalendar[$MonthKey][$DayKey] = ""
163
}
164
165
$HolidayCalendar[$MonthKey][$DayKey] = $Holiday
166
}
167
168
if ($MemArray[-1]) {
169
170
$Memday = $MemArray[-1]
171
172
$HolidayCalendar[5][$Memday] = "Memorial Day"
173
}
174
}
175
176
$MthKeys = $HolidayCalendar.Keys
177
ForEach ($mk in $MthKeys | Sort-Object) {
178
179
$MonthName = (Get-Culture).DateTimeFormat.GetMonthName($mk)
180
#Write-Host $MonthName
181
182
$DayKeys = $HolidayCalendar[$mk].Keys
183
ForEach ($dk in $DayKeys | Sort-Object) {
184
185
$DateObject = Get-Date -Year $Year -Month $mk -Day $dk
186
$DayName = $DateObject.DayOfWeek.ToString()
187
188
$HolidayDesc = $null
189
if ($HolidayCalendar[$mk][$dk]) {
190
$HolidayDesc = $HolidayCalendar[$mk][$dk]
191
}
192
193
if ($DayName -eq "Saturday") {
194
$DateObject = $DateObject.AddDays(-1)
195
$DayName = $DateObject.DayOfWeek.ToString()
196
}
197
198
if ($DayName -eq "Sunday") {
199
$DateObject = $DateObject.AddDays(1)
200
$DayName = $DateObject.DayOfWeek.ToString()
201
}
202
203
$Columns = [PsCustomObject]@{
204
MonthName=$MonthName;
205
Month=$mk;
206
WeekIndex=$WeekNum[$DayName];
207
DayName=$DayName;
208
Day=$dk;
209
Year=$Year;
210
Desc=$HolidayDesc
211
}
212
213
$Rows += $Columns
214
215
}
216
}
217
return $Rows
218
}
219
220
<# Main ::
221
Merge and offset clashes.
222
#>
223
$WeekNum = @{
224
Sunday=0;
225
Monday=1;
226
Tuesday=2;
227
Wednesday=3;
228
Thursday=4;
229
Friday=5;
230
Saturday=6
231
}
232
233
$MergedRows = @()
234
$DateHash = @{}
235
236
# Ge major holidays.
237
$MyHolidays = Get-Holidays #-Year 2026
238
$MyPaydays = Get-Paydays #-Year 2026 -FirstPayMonth 1 -FirstPayDay 9
239
240
ForEach ($p in $MyPaydays) {
241
$Pdate = Get-Date -Year $p.Year -Month $p.Month -Day $p.Day
242
if (-not($DateHash.ContainsKey($Pdate.Date))) {
243
$DateHash[$Pdate.Date] = $p
244
}
245
}
246
247
ForEach ($h in $MyHolidays) {
248
if ($h.Desc) {
249
$Hdate = Get-Date -Year $h.Year -Month $h.Month -Day $h.Day
250
if (-not($DateHash.ContainsKey($Hdate.Date))) {
251
$DateHash[$Hdate.Date] = $h
252
} else {
253
$Pdate = Get-Date -Year $DateHash[$Hdate.Date].Year -Month $DateHash[$Hdate.Date].Month -Day $DateHash[$Hdate.Date].Day
254
$Pdate = $Pdate.AddDays(-1)
255
$MonthName = (Get-Culture).DateTimeFormat.GetMonthName($Pdate.Month)
256
$DayName = $Pdate.DayOfWeek.ToString()
257
$Column = [PsCustomObject]@{
258
MonthName=$MonthName;
259
Month=$Pdate.Month;
260
WeekIndex=$WeekNum[$DayName];
261
DayName=$DayName;
262
Day=$Pdate.Day;
263
Year=$Pdate.Year;
264
Desc="payday"
265
}
266
$DateHash[$Hdate.Date] = $h
267
$DateHash[$Pdate.Date] = $Column
268
}
269
}
270
}
271
272
# create report.
273
$ReportRows = @()
274
$DateKeys = $DateHash.Keys
275
ForEach ($mdate in $DateKeys | Sort-Object) {
276
Write-Host $DateHash[$mdate]
277
$ReportRows += $DateHash[$mdate]
278
}
279
# Save as CSV.
280
#$ReportRows | Export-Csv -Path "~/PrCal.csv" -NoTypeInformation
281
282
<# OUTPUT
283
@{MonthName=January; Month=1; WeekIndex=1; DayName=Monday; Day=1; Year=2024; Desc=New Year's Day}
284
@{MonthName=January; Month=1; WeekIndex=5; DayName=Friday; Day=12; Year=2024; Desc=payday}
285
@{MonthName=January; Month=1; WeekIndex=1; DayName=Monday; Day=15; Year=2024; Desc=Martin Luther King, Jr.Birthday}
286
@{MonthName=January; Month=1; WeekIndex=5; DayName=Friday; Day=26; Year=2024; Desc=payday}
287
@{MonthName=February; Month=2; WeekIndex=5; DayName=Friday; Day=9; Year=2024; Desc=payday}
288
@{MonthName=February; Month=2; WeekIndex=1; DayName=Monday; Day=19; Year=2024; Desc=President's Day}
289
@{MonthName=February; Month=2; WeekIndex=5; DayName=Friday; Day=23; Year=2024; Desc=payday}
290
@{MonthName=March; Month=3; WeekIndex=5; DayName=Friday; Day=8; Year=2024; Desc=payday}
291
@{MonthName=March; Month=3; WeekIndex=5; DayName=Friday; Day=22; Year=2024; Desc=payday}
292
@{MonthName=April; Month=4; WeekIndex=5; DayName=Friday; Day=5; Year=2024; Desc=payday}
293
@{MonthName=April; Month=4; WeekIndex=5; DayName=Friday; Day=19; Year=2024; Desc=payday}
294
@{MonthName=May; Month=5; WeekIndex=5; DayName=Friday; Day=3; Year=2024; Desc=payday}
295
@{MonthName=May; Month=5; WeekIndex=5; DayName=Friday; Day=17; Year=2024; Desc=payday}
296
@{MonthName=May; Month=5; WeekIndex=1; DayName=Monday; Day=27; Year=2024; Desc=Memorial Day}
297
@{MonthName=May; Month=5; WeekIndex=5; DayName=Friday; Day=31; Year=2024; Desc=payday}
298
@{MonthName=June; Month=6; WeekIndex=5; DayName=Friday; Day=14; Year=2024; Desc=payday}
299
@{MonthName=June; Month=6; WeekIndex=3; DayName=Wednesday; Day=19; Year=2024; Desc=Juneteenth}
300
@{MonthName=June; Month=6; WeekIndex=5; DayName=Friday; Day=28; Year=2024; Desc=payday}
301
@{MonthName=July; Month=7; WeekIndex=4; DayName=Thursday; Day=4; Year=2024; Desc=Independence Day}
302
@{MonthName=July; Month=7; WeekIndex=5; DayName=Friday; Day=12; Year=2024; Desc=payday}
303
@{MonthName=July; Month=7; WeekIndex=5; DayName=Friday; Day=26; Year=2024; Desc=payday}
304
@{MonthName=August; Month=8; WeekIndex=5; DayName=Friday; Day=9; Year=2024; Desc=payday}
305
@{MonthName=August; Month=8; WeekIndex=5; DayName=Friday; Day=23; Year=2024; Desc=payday}
306
@{MonthName=September; Month=9; WeekIndex=1; DayName=Monday; Day=2; Year=2024; Desc=Labor Day}
307
@{MonthName=September; Month=9; WeekIndex=5; DayName=Friday; Day=6; Year=2024; Desc=payday}
308
@{MonthName=September; Month=9; WeekIndex=5; DayName=Friday; Day=20; Year=2024; Desc=payday}
309
@{MonthName=October; Month=10; WeekIndex=5; DayName=Friday; Day=4; Year=2024; Desc=payday}
310
@{MonthName=October; Month=10; WeekIndex=1; DayName=Monday; Day=14; Year=2024; Desc=Columbus Day}
311
@{MonthName=October; Month=10; WeekIndex=5; DayName=Friday; Day=18; Year=2024; Desc=payday}
312
@{MonthName=November; Month=11; WeekIndex=5; DayName=Friday; Day=1; Year=2024; Desc=payday}
313
@{MonthName=November; Month=11; WeekIndex=1; DayName=Monday; Day=11; Year=2024; Desc=Veteran's Day}
314
@{MonthName=November; Month=11; WeekIndex=5; DayName=Friday; Day=15; Year=2024; Desc=payday}
315
@{MonthName=November; Month=11; WeekIndex=1; DayName=Monday; Day=25; Year=2024; Desc=Thanksgiving}
316
@{MonthName=November; Month=11; WeekIndex=5; DayName=Friday; Day=29; Year=2024; Desc=payday}
317
@{MonthName=December; Month=12; WeekIndex=5; DayName=Friday; Day=13; Year=2024; Desc=payday}
318
@{MonthName=December; Month=12; WeekIndex=3; DayName=Wednesday; Day=25; Year=2024; Desc=Christmas Day}
319
@{MonthName=December; Month=12; WeekIndex=5; DayName=Friday; Day=27; Year=2024; Desc=payday}
320
#>