views:

372

answers:

3

How to find next business day with powershell ?

+8  A: 

Well, my phone allows me to set which days are business days, but Windows/.NET won't, so I assume Monday through Friday.

Note: As the question includes "golf" I am golfing this one, that is trying to use as few bytes for the script as possible. The code is not necessarily readable as a result.

The easiest and most straightforward way to do is would be to start with today, add a day and look whether it is in the wanted range:

PS> $d = [DateTime]::Now.AddDays(1); while ($d.DayOfWeek -eq "Saturday" -or $d.DayOfWeek -eq "Sunday") { $d = $d.AddDays(1) }; $d
Montag, 22. Juni 2009 19:50:27

We can shorten that a little, though:

PS> $d=(Get-Date)+"1";for(;6,0-contains$d.DayOfWeek){$d+="1"}$d
Montag, 22. Juni 2009 19:52:31

But we can also try it differently, using the pipeline. The next business day is at least one and at most three days away, so we can generate a list of possible dates and filter them accordingly and at last, select the first one:

PS> @(1..3|%{(Get-Date).AddDays($_)}|?{$_.DayOfWeek -ge "Monday" -and $_.DayOfWeek -le "Friday"})[0]
Montag, 22. Juni 2009 22:11:19

or shorter:

PS> @(1..3|%{(Get-Date)+"$_"}|?{1..5-contains$_.DayOfWeek})[0]
Montag, 22. Juni 2009 19:55:53

By letting the range go to 4 we can guarantee that it always returns at least two workdays and save the @ operator to force an array:

PS> (1..4|%{(Get-Date)+"$_"}|?{1..5-contains$_.DayOfWeek})[0]
Montag, 22. Juni 2009 20:24:06
Joey
i like those pipelined versions, first two versions have two statements, thanks a lot
m1k4
Well, didn't know that more than one statement was forbidden.
Joey
+1  A: 

Here is another pipline way:

(@(1..4) | foreach { if (([datetime]::Now.AddDays($_)).DayOfWeek -ne "Sunday" -and ([datetime]::Now.AddDays($_)).DayOfWeek -ne "Saturday") {[datetime]::Now.AddDays($_); }})[0]

Not sure why I have to use (1..4) instead of (1..3) however.

wtjones
Well, that's obvious. If the current day is a Friday, you're getting only one result back (the following Monday), which will be returned as a single object, not as an array which is why you can't index into it using [0]. When you use 1..4 (you can drop the @() around that, by the way) you're getting two dates, that is, an array where you _can_ pick the first one. Another option would be to put @() around the complete statement (see my answer) to force an array (even with only one item) where you can use [0] again.
Joey
+4  A: 

This is pretty short too (but uses aliases):

,(1,2-eq7-(date).dayofweek)|%{(date)+"$(1+$_[0])"}

In one single statement:

(date)+"$(1+$(@(1,2-eq7-(date).dayofweek)))"


A few notes about this approach:

  • In Powershell (v1 at least), comparisons with collections return items where the condition is true, for example:

    PS> 1,2 -eq 1
    PS> 1

  • I'm taking advantage of the fact that the actual exceptions to the rule today + 1 to calculate the next business day are only Friday (+3 days) and Saturday (+2 days).

guillermooo
excellent, this should be the right answer, but I needed this quickly...i'm powershell rookie; didn't know for date alias :)
m1k4
I'm going to sound like an ass, but you can change the accepted answer anytime on SO. You might as well wait, though, since maybe someone else will come up with an even more compact onliner. Some developers from the Microsoft Powershell Team are on SO too...
guillermooo