Skip to content

Instantly share code, notes, and snippets.

@codaamok
Last active April 12, 2022 09:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save codaamok/ceb07be03b0ac2b9f022bcfda58fe69e to your computer and use it in GitHub Desktop.
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
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