-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathWrite-Calendar.ps1
More file actions
294 lines (235 loc) · 10.1 KB
/
Write-Calendar.ps1
File metadata and controls
294 lines (235 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
<#
.SYNOPSIS
Writes out calendar elements, either a single month or an entire year depending on the inputs.
.PARAMETER Month
If specified, will limit output to a single month with this numeral value.
.PARAMETER Year
If specified, will output an entire year.
.PARAMETER ShowHolidays
If specified, holidays for the year and month are shown.
.PARAMETER ObservedHolidays
If specified with the ShowHolidays flag, observed holidays will be shown instead of the actual dates.
.PARAMETER $DateColors
A [ConsoleColor] array of two elements specifying the foreground color and background color for each day printed
.PARAMETER $TodayColors
A [ConsoleColor] array of two elements specifying the foreground color and background color for today's date
.PARAMETER $HolidayColors
A [ConsoleColor] array of two elements specifying the foreground color and background color for holidays printed
.NOTES
This script has some functionality which many would consider weird or inconsistent. Specifically, if a month is specifed and a year is not, then the output is typically the calendar for the input month and the current year. However, if the specified month is greater than 12, then it's treated as a year and the whole year is outputted.
The reason for this is to emulate the *NIX cal function, which behaves similarly. That is, cal outputs the current month, cal 2012 outpus the calendar for 2012 and cal 05 2012 outputs the calendar for May 2012.
That is pretty much how Write-Calendar works with the exception that Write-Calendar 05 will write out the calendar for May of the current year whereas cal will output the calendar for the year 5.
Since the point of this script is to emulate cal's functionality I will probably not change it to make it more consistent.
.EXAMPLE
Write-Calendar
Outputs the current month.
.EXAMPLE
Write-Calendar 2013
Outputs the calendar for 2013.
.EXAMPLE
Write-Calendar 04 2011
Outputs the calendar for April, 2011.
.EXAMPLE
Write-Calendar 7
Outputs the calendar for September of this year.
#>
param (
[int] $Month = (Get-Date).Month,
[int] $Year = (Get-Date).Year,
[switch] $ShowHolidays,
[switch] $ObservedHolidays,
[ConsoleColor[]] $DateColors = @([ConsoleColor]::White, [Console]::BackgroundColor),
[ConsoleColor[]] $TodayColors = @([ConsoleColor]::Red, [Console]::BackgroundColor),
[ConsoleColor[]] $HolidayColors = @([ConsoleColor]::White, [ConsoleColor]::DarkCyan)
)
Set-Variable -name daysLine -option Constant -value "Su Mo Tu We Th Fr Sa "
if ($year -lt 0) {
throw "Year parameter must be greater than 0"
}
if ($month -lt 0) {
throw "Month parameter must be between 1 and 12"
}
if (($month -gt 12) -and ($year -eq (Get-Date).Year)) {
$year = $month
$month = 0
}
elseif (($month -gt 12) -and ($year -ne (Get-Date).Year)) {
throw "Month parameter must be between 1 and 12"
}
foreach ($array in @($DateColors, $TodayColors, $HolidayColors)) {
if ($array.Length -lt 2) {
throw "Must specify both foreground and background colors for color parameters"
}
}
function Print-Month ($month, $year) {
$firstDayOfMonth = Get-Date -month $month -day 1 -year $year
$lastDayOfMonth = (Get-Date -month $firstDayOfMonth.AddMonths(1).Month -day 1 -year $firstDayOfMonth.AddMonths(1).Year).AddDays(-1)
$header = (Get-Date $firstDayOfMonth -Format MMMM) + " " + $firstDayOfMonth.Year
Write-Host
Write-Host ((" " * (($daysLine.Length - $header.Length) / 2)) + $header)
Write-Host $daysLine
for ($day = $firstDayOfMonth; $day -le $lastDayOfMonth; $day = $day.AddDays(1)) {
$ForegroundColor = $DateColors[0]
$BackgroundColor = $DateColors[1]
if ($day.date -eq (get-date).date) {
$ForegroundColor = $TodayColors[0]
$BackgroundColor = $TodayColors[1]
}
elseif ($ShowHolidays.IsPresent) {
if ((Get-Holidays $year).Contains($day.Date)) {
$ForegroundColor = $HolidayColors[0]
$BackgroundColor = $HolidayColors[1]
}
}
if ($day.day -eq 1) {
Write-Host (" " * 3 * [int](Get-Date $day -uformat %u)) -NoNewLine
}
Write-Host ((Get-Date $day -Format dd).ToString()) -NoNewLine -ForegroundColor $ForegroundColor -BackgroundColor $BackgroundColor
Write-Host " " -NoNewLine
if ($day.DayOfWeek -eq "Saturday") {
Write-Host
}
}
if ($lastDayOfMonth.DayOfWeek -ne "Saturday") {
Write-Host
}
Write-Host
}
function Print-Year ($year) {
if ($ShowHolidays.IsPresent) {
$holidays = Get-Holidays $year
}
Write-Host
for($month = 1; $month -le 12; $month += 3) {
$header = ""
for ($i = $month; $i -lt $month + 3; $i++) {
$tempHeader = (Get-Date -month $i -Format MMMM) + " " + $year.ToString()
$header += ((" " * (($daysLine.Length - $tempHeader.Length) / 2)) + $tempHeader + (" " * (($daysLine.Length - $tempHeader.Length) / 2)))
$header += " "
}
Write-Host $header
Write-Host (($daysLine + " ") * 3)
$dayCounts = (1, 1, 1)
$i = 0
while ($dayCounts[0] -le (Get-Date -day 1 -month ($month + 1) -year $year).AddDays(-1).day -or `
$dayCounts[1] -le (Get-Date -day 1 -month ($month + 2) -year $year).AddDays(-1).day -or `
$dayCounts[2] -le (Get-Date -day 1 -month (($month + 3) % 12) -year $year).AddDays(-1).day) {
$dayOfMonth = $dayCounts[$i]
$dayCounts[$i]++
$dayOffset = [int](Get-Date -day 1 -month ($month + $i) -year $year -uformat %u)
$ForegroundColor = $DateColors[0]
$BackgroundColor = $DateColors[1]
if ($dayOfMonth -eq 1) {
Write-Host (" " * 3 * $dayOffSet) -NoNewLine
}
if ($dayOfMonth -le (Get-Date -day 1 -month ((($i + $month) % 12) + 1) -year $year).AddDays(-1).day) {
$currentDay = (Get-Date -day $dayOfMonth -month ((($i + $month - 1) % 12) + 1) -year $year)
if ($currentDay.date -eq (Get-Date).date) {
$ForegroundColor = $TodayColors[0]
$BackgroundColor = $TodayColors[1]
}
elseif ($ShowHolidays.IsPresent) {
if ($holidays.Contains($currentDay.Date)) {
$ForegroundColor = $HolidayColors[0]
$BackgroundColor = $HolidayColors[1]
}
}
Write-Host ((Get-Date -month ($i + $month) -day $dayOfMonth -year $year -Format dd).ToString()) -NoNewLine -ForegroundColor $ForegroundColor -BackgroundColor $BackgroundColor
Write-Host " " -NoNewLine
}
else {
Write-Host " " -NoNewLine
}
if ((($dayOfMonth + $dayOffset) % 7) -eq 0) {
$i = ($i + 1) % 3
Write-Host " " -NoNewLine
if ($i -eq 0) {
Write-Host
}
}
}
Write-Host
$dayCounts = (1, 1, 1)
}
}
function Get-Holidays ($year) {
$holidays = @(
Get-Date -Year $year -Month 1 -Day 1 # New Year's Day
Find-WeekDayMultiple $year 1 "Monday" 3 # MLK Day
Find-WeekDayMultiple $year 2 "Monday" 3 # President's Day
Find-GoodFriday $year # Good Friday
Find-LastWeekDay $year 5 "Monday" # Memorial Day
Get-Date -Year $year -Month 7 -Day 4 # Fourth of July
Find-WeekDayMultiple $year 9 "Monday" 1 # Labor Day
Find-WeekDayMultiple $year 10 "Monday" 2 # Columbus Day
Get-Date -Year $year -Month 11 -Day 11 # Veterans Day
Find-WeekDayMultiple $year 11 "Thursday" 4 # Thanksgiving
Get-Date -Year $year -Month 12 -Day 25 # Christmas
) |% {$_.Date}
if ($ObservedHolidays.IsPresent) {
return $holidays |% {Find-ObservedHoliday $_}
}
else {
return $holidays
}
}
function Find-WeekDayMultiple ($year, $month, $dayOfWeek, $multiple) {
$result = Get-Date -Year $year -Month $month -Day 1
$multipleCount = 0
do {
if ($result.DayOfWeek -eq $dayOfWeek) {
$multipleCount++
}
$result = $result.AddDays(1)
if ($result.Month -ne $month) {
throw "Could not find weekday multiple."
}
}
while ($multipleCount -lt $multiple)
return $result.AddDays(-1)
}
function Find-LastWeekDay ($year, $month, $dayOfWeek) {
$result = $dayCounter = Get-Date -Year $year -Month $month -Day 1
while ($dayCounter.Month -eq $month) {
if ($dayCounter.DayOfWeek -eq $dayOfWeek) {
$result = $dayCounter
}
$dayCounter = $dayCounter.AddDays(1)
}
return $result
}
function Find-GoodFriday ($year) {
# Taken from http://en.wikipedia.org/wiki/Computus#Anonymous_Gregorian_algorithm
$a = $year % 19
$b = [Math]::Floor($year / 100)
$c = $year % 100
$d = [Math]::Floor($b / 4)
$e = $b % 4
$f = [Math]::Floor(($b + 8) / 25)
$g = [Math]::Floor(($b - $f + 1) / 3)
$h = (19 * $a + $b - $d - $g + 15) % 30
$i = [Math]::Floor($c / 4)
$k = $c % 4
$L = (32 + 2 * $e + 2 * $i - $h - $k) % 7
$m = [Math]::Floor(($a + 11 * $h + 22 * $L) / 451)
$month = [Math]::Floor(($h + $L - 7 * $m + 114) / 31)
$day = (($h + $L - 7 * $m + 114) % 31) + 1
return (Get-Date -Year $year -Month $month -Day $day).AddDays(-2)
}
function Find-ObservedHoliday ($holiday) {
if ($holiday.DayOfWeek -eq "Saturday") {
return $holiday.AddDays(-1)
}
elseif ($holiday.DayOfWeek -eq "Sunday") {
return $holiday.AddDays(1)
}
else {
return $holiday
}
}
if ($month -ne 0) {
Print-Month $month $year
}
else {
Print-Year $year
}