1

I need to find the date of the third saturday of the month.

I've got the following function, which finds me the last saturday of the month

function Get-3rdSaturdayOfMonth {
    $Date = Get-Date
    $lastDay = new-object DateTime($Date.Year, $Date.Month, [DateTime]::DaysInMonth($Date.Year, $Date.Month))
    $diff = ([int] [DayOfWeek]::Saturday) - ([int] $lastDay.DayOfWeek)
    if ($diff -ge 0) {
        return $lastDay.AddDays(- (7-$diff))
    }
    else {
        return $lastDay.AddDays($diff)
    }
}

However, I don't know how to edit it to find the third saturday of the month.

Right now the function goes from last date of the month to the saturday that comes before it. But if I want the third saturday i think i need to calculate from the first day of the month, not the last.

SimonS
  • 1,891
  • 1
  • 29
  • 53

2 Answers2

2

Based on the solution from Brandon, since the third Saturday can't possibly occur before the 15th of the month, we can increment from the 15. until we find a saturday:

$thirdSaturday = [DateTime]::new((Get-Date).Year,(Get-Date).Month,15)
while ($thirdSaturday.DayOfWeek -ne [DayOfWeek]::Saturday) 
{
    $thirdSaturday = $thirdSaturday.AddDays(1)
}
Martin Brandl
  • 56,134
  • 13
  • 133
  • 172
0

Adding onto Martin's answer, since the third Saturday MUST be between the 15th and 21st of the month (inclusive) we can write a simple one-liner as such:

15..21 | % {get-date -Day $_} | ? {$_.DayOfWeek -eq "Saturday"}

or for a particular year/month (we'll use January), just insert that as such:

15..21 | % {get-date "01/01/2023" -Day $_} | ? {$_.DayOfWeek -eq "Saturday"}

The output is still a DateTime object that can be used however you would like.

I couldn't leave this alone...

Function Get-NthDayofMonth {
    [cmdletbinding()]
    # This function came about from someone wanting the 3rd Saturday of the month (we'll use January).
    # I came up with the following one-liner:
    # 15..21 | % {get-date "01/01/2023" -Day $_} | ? {$_.DayOfWeek -eq "Saturday"}
    # After that I couldn't leave well enough alone and so created this function.
    param(
        # Validate the occurrence range
        [Parameter(Mandatory = $True, Position = 0)]
        [ValidateRange(1,5)]
        [Int]$NthOccurrence,
        # Validate the day of the week
        [Parameter(Mandatory = $True, Position = 1)]
        [ValidateSet("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday")]
        [String]$DayOfWeek,
        # Validate and set month (default current month)
        [ValidateRange(1,12)]
        [Int]$Month = (Get-Date).Month,
        # Validate and set year (default current year)
        [ValidateRange(1900,2100)]
        [Int]$Year = (Get-Date).Year
    )
    Begin {
        # Each occurrence can ONLY fall within specific dates.  We set those ranges here.
        Write-Verbose "Getting `$NthOccurrence ($NthOccurrence) range"
        # COULD just do $(($NthOccurrence*7)-6)..$($NthOccurrence*7) but I like seeing the ranges in the code
        $Nth = switch ($NthOccurrence) {
            1  {1..7}
            2  {8..14}
            3  {15..21}
            4  {22..28}
            5  {29..31}
        }
        Write-Verbose "`$NthOccurrence range is: $($Nth[0])..$($Nth[6])"
        Write-Verbose "Getting `$Month and `$Year date"
        # Get a DateTime object for the selected Month/Year
        $MonthYear = [DateTime]::new($Year, $Month, 1)
        Write-Verbose $MonthYear
    }
    Process {
        Write-Verbose "Getting occurrence $NthOccurrence of weekday $DayOfWeek in $($MonthYear.ToLongDateString().Split(',')[1].Trim().Split(' ')[0]) of $Year"
        # Get the day of the week for each date in range and select the desired one
        foreach ($Day in $Nth) {
            Get-Date $MonthYear -Day $Day | Where-Object {$_.DayOfWeek -eq $DayOfWeek}
        }
    }
    End {
    }
}

Provides this output when used:

PS H:\> Get-NthDayofMonth 4 Saturday -Month 2 -Verbose
VERBOSE: Getting $NthOccurrence (4) range
VERBOSE: $NthOccurrence range is: 22..28
VERBOSE: Getting $Month and $Year date
VERBOSE: 02/01/2023 00:00:00
VERBOSE: Getting occurrence 4 of weekday Saturday in February of 2023

Saturday, February 25, 2023 12:00:00 AM
James K
  • 1
  • 1