Private/DateMath.ps1
|
function Get-BCMonthBound { [CmdletBinding()] param([Parameter(Mandatory)][ValidateRange(1,9999)][int]$Year, [Parameter(Mandatory)][ValidateRange(1,12)][int]$Month) $start = [datetime]::new($Year,$Month,1) $end = [datetime]::new($Year,$Month,[datetime]::DaysInMonth($Year,$Month)) [pscustomobject]@{ Start=$start; End=$end; Days=[datetime]::DaysInMonth($Year,$Month) } } function ConvertTo-BCWeekdayNumber { param([Parameter(Mandatory)][string]$Weekday) $map = @{ Sunday=0; Monday=1; Tuesday=2; Wednesday=3; Thursday=4; Friday=5; Saturday=6 } return [int]$map[$Weekday] } function Get-BCGridCell { [CmdletBinding()] param( [Parameter(Mandatory)][int]$Year, [Parameter(Mandatory)][int]$Month, [Parameter(Mandatory)][ValidateSet('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday')][string]$WeekStart, [Parameter(Mandatory)][ValidateSet('FixedSixWeeks','Compact')][string]$Layout, [Parameter(Mandatory)][ValidateSet('Adjacent','Blank')][string]$Overflow, [datetime[]]$SpecialDate = @() ) $bounds = Get-BCMonthBound -Year $Year -Month $Month $weekStartNumber=ConvertTo-BCWeekdayNumber $WeekStart $firstOffset = (([int]$bounds.Start.DayOfWeek - $weekStartNumber) + 7) % 7 $monthFirstOrdinal=[int](($bounds.Start-[datetime]::MinValue).TotalDays) $monthLastOrdinal=[int](($bounds.End-[datetime]::MinValue).TotalDays) $maxOrdinal=[int](([datetime]::MaxValue.Date-[datetime]::MinValue).TotalDays) $rows = if ($Layout -eq 'FixedSixWeeks') { 6 } else { [int][math]::Ceiling(($firstOffset + $bounds.Days) / 7) } for ($index=0; $index -lt ($rows * 7); $index++) { $ordinal=$monthFirstOrdinal+$index-$firstOffset $isRepresentable=$ordinal -ge 0 -and $ordinal -le $maxOrdinal $date=if($isRepresentable){$bounds.Start.AddDays($index-$firstOffset)}else{$null} $inMonth = $ordinal -ge $monthFirstOrdinal -and $ordinal -le $monthLastOrdinal $hasDate = ($inMonth -or $Overflow -eq 'Adjacent') -and $isRepresentable $weekday=[DayOfWeek](($weekStartNumber+$index%7)%7) $special = $false foreach ($item in $SpecialDate) { if ($item.Date -eq $date.Date) { $special = $true; break } } $weekYear = 0; $week = 0 if ($hasDate) { $iso = [Globalization.ISOWeek]::GetYear($date); $weekYear = $iso; $week = [Globalization.ISOWeek]::GetWeekOfYear($date) } [pscustomobject][ordered]@{ Date = if ($hasDate) { $date } else { $null } Year = if ($hasDate) { $date.Year } else { $null } Month = if ($hasDate) { $date.Month } else { $null } Day = if ($hasDate) { $date.Day } else { $null } Weekday = [string]$weekday Row = [int][math]::Floor($index / 7) Column = $index % 7 InMonth = $inMonth IsWeekend = $weekday -in @([DayOfWeek]::Saturday,[DayOfWeek]::Sunday) IsMonthStart = $hasDate -and $inMonth -and $date.Day -eq 1 IsMonthEnd = $hasDate -and $inMonth -and $date.Day -eq $bounds.Days IsYearStart = $hasDate -and $date.Month -eq 1 -and $date.Day -eq 1 IsYearEnd = $hasDate -and $date.Month -eq 12 -and $date.Day -eq 31 ISOWeek = if ($hasDate) { $week } else { $null } ISOWeekYear = if ($hasDate) { $weekYear } else { $null } IsSpecialDate = $hasDate -and $special } } } function Get-BCDayOfMonth { param([int]$Year,[int]$Month,[int]$Day,[ValidateSet('Skip','Clamp','Error')][string]$Policy) $last = [datetime]::DaysInMonth($Year,$Month) if ($Day -le $last) { return $Day } switch ($Policy) { Skip { return 0 } Clamp { return $last } Error { throw "Day $Day does not exist in $Year-$('{0:d2}' -f $Month)." } } } |