Last active
April 12, 2022 09:12
-
-
Save codaamok/ceb07be03b0ac2b9f022bcfda58fe69e to your computer and use it in GitHub Desktop.
The below code is old and was made during initial development, it is now module PSBusinessTime https://github.com/codaamok/psbusinesstime
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
BeforeAll { | |
function GetElapsedTime { | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory)] | |
[DateTime]$StartDate, | |
[Parameter(Mandatory)] | |
[DateTime]$EndDate, | |
[Parameter(Mandatory)] | |
[DateTime]$StartOfDay, | |
[Parameter(Mandatory)] | |
[DateTime]$EndOfDay | |
) | |
$Subtractor = New-TimeSpan | |
$StartOfDayDifference = $StartOfDay.TimeOfDay - $StartDate.TimeOfDay | |
if ($StartOfDayDifference -gt 0) { | |
$Subtractor += $StartOfDayDifference | |
} | |
$EndOfDayDifference = $EndDate.TimeOfDay - $EndOfDay.TimeOfDay | |
if ($EndOfDayDifference -gt 0) { | |
$Subtractor += $EndOfDayDifference | |
} | |
(New-TimeSpan -Start $StartDate -End $EndDate) - $Subtractor | |
} | |
function Test-WorkingDay { | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory)] | |
[DateTime]$StartDate, | |
[Parameter()] | |
[DateTime]$StartHour = '08:00:00', | |
[Parameter()] | |
[DateTime]$FinishHour = '17:00:00', | |
[Parameter()] | |
[int[]]$NonWorkingDaysOfWeek = @(0,6), | |
[Parameter()] | |
[DateTime[]]$NonWorkingDates = @() | |
) | |
$NonWorkingDaysOfWeek -notcontains $StartDate.DayOfWeek -And | |
$StartDate.TimeOfDay -ge $StartHour.TimeOfDay -And | |
$StartDate.TimeOfDay -lt $FinishHour.TimeOfDay -And | |
$NonWorkingDates -notcontains $StartDate.Date | |
} | |
function Get-WorkingDays { | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory)] | |
[DateTime]$StartDate, | |
[Parameter(Mandatory)] | |
[ValidateScript({ | |
if ($StartDate -gt $_) { throw "-StartDate must be less than -EndDate." } else { return $true } | |
})] | |
[DateTime]$EndDate, | |
[Parameter()] | |
[int[]]$NonWorkingDaysOfWeek = @(0,6), | |
[Parameter()] | |
[DateTime[]]$NonWorkingDates = @() | |
) | |
if ($StartDate.TimeOfDay -eq $EndDate.TimeOfDay) { | |
# This can return 1 less than intended if we do not do this change. | |
# For example, if the dates in between are 3 working days, | |
# but the time span between them are 2 whole days, | |
# this returns 2 instead of 3 | |
$EndDate = $EndDate.AddSeconds(1) | |
} | |
$TimeSpan = New-TimeSpan -Start $StartDate -End $EndDate | |
$Days = [Math]::Ceiling($TimeSpan.TotalDays) | |
$Date = $StartDate | |
$WorkingDays = do { | |
if ($NonWorkingDaysOfWeek -notcontains $Date.DayOfWeek -And $NonWorkingDates -notcontains $Date.Date) { | |
$Date | |
} | |
$Date = $Date.AddDays(1) | |
$Days-- | |
} while ($Days) | |
$WorkingDays.Count | |
} | |
function Get-ElapsedBusinessTime { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory)] | |
[datetime]$StartDate, | |
[Parameter(Mandatory)] | |
[ValidateScript({ | |
if ($StartDate -gt $_) { throw "-StartDate must be less than -EndDate." } else { return $true } | |
})] | |
[datetime]$EndDate, | |
[Parameter()] | |
[DateTime]$StartOfDay = '08:00:00', | |
[Parameter()] | |
[DateTime]$EndOfDay = '17:00:00', | |
[Parameter()] | |
[int[]]$NonWorkingDaysOfWeek = @(0,6), | |
[Parameter()] | |
[DateTime[]]$NonWorkingDates = @() | |
) | |
$CommonParams = @{ | |
NonWorkingDaysOfWeek = $NonWorkingDaysOfWeek | |
NonWorkingDates = $NonWorkingDates | |
} | |
$WorkingHours = New-TimeSpan -Start $StartOfDay -End $EndOfDay | |
$WorkingDays = Get-WorkingDays -StartDate $StartDate -EndDate $EndDate @CommonParams | |
if ($WorkingDays -eq 0) { | |
New-TimeSpan | |
} | |
elseif ($WorkingDays -eq 1) { | |
$Params = @{ | |
StartDate = $StartDate | |
EndDate = $EndDate | |
StartOfDay = $StartOfDay | |
EndOfDay = $EndOfDay | |
} | |
GetElapsedTime @Params | |
} | |
else { | |
$ElapsedTime = New-TimeSpan | |
if (Test-WorkingDay -StartDate $StartDate -StartHour $StartOfDay -FinishHour $EndOfDay @CommonParams) { | |
$FirstDayEndDate = Get-Date ('{0}/{1}/{2} {3}:{4}:{5}' -f $StartDate.Year, | |
$StartDate.Month, | |
$StartDate.Day, | |
$EndOfDay.Hour, | |
$EndOfDay.Minute, | |
$EndOfDay.Second) | |
$Params = @{ | |
StartDate = $StartDate | |
EndDate = $FirstDayEndDate | |
StartOfDay = $StartOfDay | |
EndOfDay = $EndOfDay | |
} | |
$ElapsedTime += (GetElapsedTime @Params) | |
$WorkingDays-- | |
} | |
if (Test-WorkingDay -StartDate $EndDate -StartHour $StartOfDay -FinishHour $EndOfDay @CommonParams) { | |
$LastDayStartDate = Get-Date ('{0}/{1}/{2} {3}:{4}:{5}' -f $EndDate.Year, | |
$EndDate.Month, | |
$EndDate.Day, | |
$StartOfDay.Hour, | |
$StartOfDay.Minute, | |
$StartOfDay.Second) | |
$Params = @{ | |
StartDate = $LastDayStartDate | |
EndDate = $EndDate | |
StartOfDay = $StartOfDay | |
EndOfDay = $EndOfDay | |
} | |
$ElapsedTime += (GetElapsedTime @Params) | |
$WorkingDays-- | |
} | |
$InBetweenHours = $WorkingDays * $WorkingHours.Hours | |
(New-TimeSpan -Hours $InBetweenHours) + $ElapsedTime | |
} | |
} | |
} | |
Describe "Test-WorkingDay" { | |
It "Should be a working day: <_.Description>" -TestCases @( | |
@{ | |
StartDate = Get-Date '2022-04-07 10:00:00' | |
StartHour = Get-Date '08:00:00' | |
FinishHour = Get-Date '17:00:00' | |
Description = 'traditional work day and time' | |
} | |
@{ | |
StartDate = Get-Date '2022-04-07 01:00:00' | |
StartHour = Get-Date '01:00:00' | |
FinishHour = Get-Date '17:00:00' | |
Description = 'alternative starting work hour' | |
} | |
@{ | |
StartDate = Get-Date '2022-04-07 22:00:00' | |
StartHour = Get-Date '08:00:00' | |
FinishHour = Get-Date '23:00:00' | |
Description = 'alternative finishing work hour' | |
} | |
) { | |
$Params = @{ | |
StartDate = $StartDate | |
StartHour = $StartHour | |
FinishHour = $FinishHour | |
} | |
Test-WorkingDay @Params | Should -BeTrue | |
} | |
It "Should not be a working day: <_.Description>" -TestCases @( | |
@{ | |
StartDate = Get-Date '2022-04-10 10:00:00' | |
NonWorkingDates = $null | |
NonWorkingDaysOfWeek = 0,6 | |
Description = 'weekend' | |
} | |
@{ | |
StartDate = Get-Date '2022-04-07 10:00:00' | |
NonWorkingDates = Get-Date '2022-04-07' | |
NonWorkingDaysOfWeek = 0,6 | |
Description = 'non-working date eg public holiday' | |
} | |
@{ | |
StartDate = Get-Date '2022-04-07 10:00:00' | |
NonWorkingDates = $null | |
NonWorkingDaysOfWeek = 4 | |
Description = 'alternative non-working day of the week' | |
} | |
) { | |
$Params = @{ | |
StartDate = $StartDate | |
NonWorkingDates = $NonWorkingDates | |
NonWorkingDaysOfWeek = $NonWorkingDaysOfWeek | |
} | |
Test-WorkingDay @Params | Should -BeFalse | |
} | |
} | |
Describe "Get-WorkingDays" { | |
It "should be 0 working days" { | |
$StartDate = Get-Date '2022-04-09 08:00:00' | |
$EndDate = Get-Date '2022-04-09 17:00:00' | |
Get-WorkingDays -StartDate $StartDate -EndDate $EndDate | Should -Be 0 | |
} | |
It "should be 1 working day" { | |
$StartDate = Get-Date '2022-04-07 08:00:00' | |
$EndDate = Get-Date '2022-04-07 17:00:00' | |
Get-WorkingDays -StartDate $StartDate -EndDate $EndDate | Should -Be 1 | |
} | |
It "should be 2 working days across 2 consecutive days" { | |
$StartDate = Get-Date '2022-04-07 08:00:00' | |
$EndDate = Get-Date '2022-04-08 17:00:00' | |
Get-WorkingDays -StartDate $StartDate -EndDate $EndDate | Should -Be 2 | |
} | |
It "should be 2 working days across 3 consecutive days, with traditional weekends" { | |
$StartDate = Get-Date '2022-04-07 08:00:00' | |
$EndDate = Get-Date '2022-04-09 17:00:00' | |
Get-WorkingDays -StartDate $StartDate -EndDate $EndDate | Should -Be 2 | |
} | |
It "should be 10 working days across 14 consecutive days, with traditional weekends" { | |
$StartDate = Get-Date '2022-04-04 08:00:00' | |
$EndDate = Get-Date '2022-04-17 17:00:00' | |
Get-WorkingDays -StartDate $StartDate -EndDate $EndDate | Should -Be 10 | |
} | |
It "should be 9 working days across 14 consecutive days, where a date inbetween is a non-working date eg public holiday" { | |
$StartDate = Get-Date '2022-04-04 08:00:00' | |
$EndDate = Get-Date '2022-04-17 17:00:00' | |
$NonWorkingDates = Get-Date '2022-04-05' | |
Get-WorkingDays -StartDate $StartDate -EndDate $EndDate -NonWorkingDates $NonWorkingDates | Should -Be 9 | |
} | |
It "should be 8 working days across 14 consecutive days, where Sat+Sun+Mon are non-working days" { | |
$StartDate = Get-Date '2022-04-04 08:00:00' | |
$EndDate = Get-Date '2022-04-17 17:00:00' | |
Get-WorkingDays -StartDate $StartDate -EndDate $EndDate -NonWorkingDaysOfWeek 0,1,6 | Should -Be 8 | |
} | |
} | |
Describe "Get-ElapsedBusinessTime" { | |
Context "Date times which start and end within working hours" { | |
It "should be 37 minutes on the same day" { | |
$StartDate = Get-Date '2022-04-07 10:00:00' | |
$EndDate = Get-Date '2022-04-07 10:37:00' | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate).Minutes | Should -Be 37 | |
} | |
It "should be 2 hours on the same day" { | |
$StartDate = Get-Date '2022-04-07 10:00:00' | |
$EndDate = Get-Date '2022-04-07 12:00:00' | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate).Hours | Should -Be 2 | |
} | |
It "should be 9 hours on the same day" { | |
$StartDate = Get-Date '2022-04-07 08:00:00' | |
$EndDate = Get-Date '2022-04-07 17:00:00' | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate).Hours | Should -Be 9 | |
} | |
It "should be 9 hours, across 2 consecutive days, where both are working days" { | |
$StartDate = Get-Date '2022-04-07 08:00:00' | |
$EndDate = Get-Date '2022-04-08 08:00:00' | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate).Hours | Should -Be 9 } | |
It "should be 10 hours, across 1 full day and 1 partial day, where both are working days" { | |
$StartDate = Get-Date '2022-04-07 08:00:00' | |
$EndDate = Get-Date '2022-04-08 09:00:00' | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate).Hours | Should -Be 10 | |
} | |
It "should be 10 hours, across 1 partial day and 1 full day, where both are working days" { | |
$StartDate = Get-Date '2022-04-07 16:00:00' | |
$EndDate = Get-Date '2022-04-08 17:00:00' | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate).Hours | Should -Be 10 | |
} | |
It "should be 18 hours, across 2 consecutive days, where both are working days" { | |
$StartDate = Get-Date '2022-04-07 08:00:00' | |
$EndDate = Get-Date '2022-04-08 17:00:00' | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate).Hours | Should -Be 18 | |
} | |
It "should be 18 hours, across 3 consecutive days, where all are working days" { | |
$StartDate = Get-Date '2022-04-06 13:00:00' | |
$EndDate = Get-Date '2022-04-08 13:00:00' | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate).Hours | Should -Be 18 | |
} | |
It "should be 45 hours, across 5 consecutive days, where all are working days" { | |
$StartDate = Get-Date '2022-04-04 08:00:00' | |
$EndDate = Get-Date '2022-04-08 17:00:00' | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate).TotalHours | Should -Be 45 | |
} | |
It "should be 45 hours, across 7 consecutive days, where 5 are working days and 2 are not" { | |
$StartDate = Get-Date '2022-04-07 08:00:00' | |
$EndDate = Get-Date '2022-04-13 17:00:00' | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate).TotalHours | Should -Be 45 | |
} | |
It "should be 90 hours, across 14 consecutive days, where 10 are working days and 4 are not" { | |
$StartDate = Get-Date '2022-04-07 08:00:00' | |
$EndDate = Get-Date '2022-04-20 17:00:00' | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate).TotalHours | Should -Be 90 | |
} | |
It "should be 90 hours, across 17 consecutive days, where 13 are working days and 6 are not" { | |
$StartDate = Get-Date '2022-04-07 08:00:00' | |
$EndDate = Get-Date '2022-04-25 17:00:00' | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate).TotalHours | Should -Be 117 | |
} | |
It "should be 171 hours, across 29 consecutive days, where 19 are working days and 11 are not" { | |
$StartDate = Get-Date '2022-04-01 00:00:00' | |
$EndDate = Get-Date '2022-04-30 23:59:59' | |
$NonWorkingDates = (Get-Date '2022-04-15'), (Get-Date '2022-04-18') | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate -NonWorkingDates $NonWorkingDates).TotalHours | Should -Be 171 | |
} | |
It "should be 162 hours, across 29 consecutive days, where 18 are working days and 11 are not" { | |
$StartDate = Get-Date '2022-04-02 00:00:00' | |
$EndDate = Get-Date '2022-05-01 23:59:59' | |
$NonWorkingDates = (Get-Date '2022-04-15'), (Get-Date '2022-04-18') | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate -NonWorkingDates $NonWorkingDates).TotalHours | Should -Be 162 | |
} | |
It "should be 180 hours, across 29 consecutive days, where 20 are working days and 10 are not" { | |
$StartDate = Get-Date '2022-04-02 00:00:00' | |
$EndDate = Get-Date '2022-05-01 23:59:59' | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate).TotalHours | Should -Be 180 | |
} | |
It "should be 2340 hours, across 365 consecutive days, where 260 are working days and 105 are not" { | |
$StartDate = Get-Date '2022-01-01 00:00:00' | |
$EndDate = Get-Date '2022-12-31 23:59:59' | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate).TotalHours | Should -Be 2340 | |
} | |
It "should be 2259 hours, across 365 consecutive days, where 251 are working days and 20 are not" { | |
$StartDate = Get-Date '2022-01-01 00:00:00' | |
$EndDate = Get-Date '2022-12-31 23:59:59' | |
$NonWorkingDates = @( | |
Get-Date '2022-01-03' # New Year's Day | |
Get-Date '2022-04-15' # Good Friday | |
Get-Date '2022-04-18' # Easter Monday | |
Get-Date '2022-05-02' # Early May bank Holiday | |
Get-Date '2022-06-02' # Spring bank Holiday | |
Get-Date '2022-06-03' # Platinum Jubliee bank holiday | |
Get-Date '2022-08-29' # Summer bank holiday | |
Get-Date '2022-12-26' # Boxing Day | |
Get-Date '2022-12-27' # Christmas Day | |
) | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate -NonWorkingDates $NonWorkingDates).TotalHours | Should -Be 2259 | |
} | |
It "should be 0 hours, across 365 consecutive days, where 0 are working days and 365 are not" { | |
$StartDate = Get-Date '2022-01-01 00:00:00' | |
$EndDate = Get-Date '2022-12-31 23:59:59' | |
(Get-ElapsedBusinessTime -StartDate $StartDate -EndDate $EndDate -NonWorkingDaysOfWeek (0..7)).TotalHours | Should -Be 0 | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment