Recently I was asked about a way to calculate the number of week days between two dates. It is simple enough to get the total days by subtracting two dates and then using the resulting TimeSpan object. But what if you want to skip counting Saturday and Sunday? As far as I can tell there is no .NET method to accomplish this. Now watch, as soon as I post this someone will prove me wrong.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
The technique I came up with is to start at the first date and get the day of the week for each consecutive day until the end date. If the day of the week is a weekend, don't count it.
for ($d=$Start;$d -le $end;$d=$d.AddDays(1)){
if ($d.DayOfWeek -notmatch "Sunday|Saturday") {
#if the day of the week is not a Saturday or Sunday
#increment the counter
$i++
}
...
This is a slightly different way of using a For loop and I got stuck at first until I realized I needed to manually set a new value for $d each time through. After the loop completes $i should be the total number of weekdays. Here's what my complete function looks like.
#requires -version 2.0
Function Get-TotalWeekDays {
<#
.Synopsis
Get total number of week days
.Description
Return the number of days between two dates not counting Saturday
and Sunday.
.Parameter Start
The starting date
.Parameter End
The ending date
.Example
PS C:\> Get-TotalWeekDays -start 7/1/2012 -end 7/31/2012
22
.Inputs
None
.Outputs
Integer
#>
[cmdletbinding()]
Param (
[Parameter(Position=0,Mandatory=$True,HelpMessage="What is the start date?")]
[ValidateNotNullorEmpty()]
[DateTime]$Start,
[Parameter(Position=1,Mandatory=$True,HelpMessage="What is the end date?")]
[ValidateNotNullorEmpty()]
[DateTime]$End
)
Write-Verbose -message "Starting $($myinvocation.mycommand)"
Write-Verbose -Message "Calculating number of week days between $start and $end"
#define a counter
$i=0
#test every date between start and end to see if it is a weekend
for ($d=$Start;$d -le $end;$d=$d.AddDays(1)){
if ($d.DayOfWeek -notmatch "Sunday|Saturday") {
#if the day of the week is not a Saturday or Sunday
#increment the counter
$i++
}
else {
#verify these are weekend days
Write-Verbose ("{0} is {1}" -f $d,$d.DayOfWeek)
}
} #for
#write the result to the pipeline
$i
Write-Verbose "Ending $($myinvocation.mycommand)"
} #end function
The function is pretty easy to use: provide a start and end date and it will write the number of days to the pipeline.
PS C:\> Get-TotalWeekDays -start 7/1/2012 -end 7/31/2012
22
Download Get-TotalWeekDays and let me know what you think.
Jeff – Just so you don’t get ‘Lonely’ out here.
Here is an alternate approach which is interesting.
$code=@’
using System;
public class DateMath{
public static int Weekdays(DateTime dStart, DateTime dEnd){
int startday = ((int)dStart.DayOfWeek == 0 ? 7 : (int)dStart.DayOfWeek);
int endday = ((int)dEnd.DayOfWeek == 0 ? 7 : (int)dEnd.DayOfWeek);
TimeSpan ts = dEnd – dStart;
int days = 0;
if (startday <= endday){
days = (((ts.Days / 7) * 5) + Math.Max((Math.Min((endday + 1), 6) – startday), 0));
}else{
days=(((ts.Days / 7) * 5) + Math.Min((endday + 6) – Math.Min(startday, 6), 5));
}
return days;
}
}
'@
add-Type -TypeDefinition $code
[DateMath]::Weekdays('7/1/2012','7/31/2012')
The math approach can also be done using just PowerShell.
I knew I could count on you! But that is definitely something a typical IT Pro isn’t going to figure out on their own. For a really large timespan I can see where this approach would be faster. But even my function seems plenty fast enough. A command like this Get-TotalWeekDays 1/1/2012 12/31/2015 takes less than 200ms. I can live with that.
There is a book called ‘The Encyclopedia of Algorithms’ which contains thousands of common programing algorithms. I remembered that there was this formula for caldulation weekdays in an interval. I couldn’t find teh book so I searched andfound someone who had the code onCodePLex so I updated it andd put itinto PowerShell. The math can be done in PowerSHell directly but I got lazy.
YOur version works well enough for almost all normal calculations I was just curious to see if the C# would work well in PowerShell.
Your code takes 52 ms for one year. The C# code takes .12 ms for one year and .12ms for 60 years.
Math always beats it for speed if we can find a good mathematical formula. That is what the encyclopedia is good for.
Take a look:
http://www.amazon.com/Encyclopedia-Algorithms-Springer-Reference-Ming-Yang/dp/0387307702/ref=sr_1_1?s=books&ie=UTF8&qid=1343766758&sr=1-1&keywords=0387307702
Anyway – your blog got me looking for my copy of ‘Springer’.