Поделиться через


Use PowerShell to determine the first and last days of the current calendar quarter.

Time for some fun with PowerShell. :)

***Updated to include code Eric created to determine the last day of the quarter at the bottom of this entry***

My colleague Eric Powers has PowerShell script that queries a bunch of data from the last 90 days. The intention of the script is to only collect data from the current quarter, but depending on when the script is run the last 90 days could include time (and subsequently data) from the previous quarter.

I was about to recommend he use the first day of the current calendar quarter as the start date for his query versus the day 90 days ago, but realized doing that programmatically would require some code so I set out to find some. Not finding anything relevant with my BingFu, I came up with this initial code:

 
$Today = Get-Date
$Quarter = [Math]::Ceiling($Today.Month / 3)
Switch ($Quarter) {
    1 {
        $StartDate = "1/1/" + $Today.Year.ToString()
    }
    2 {
        $StartDate = "4/1/" + $Today.Year.ToString()
    }
    3 {
        $StartDate = "7/1/" + $Today.Year.ToString()
    }
    4 {
        $StartDate = "10/1/" + $Today.Year.ToString()
    }
}

This code does the following:

  1. Grab the current date.
  2. Take the current month, divide it by 3 (dividing 12 months by 3 gives us 4 quarters of 3 months), and round-up any fractional number by using the Ceiling method in the Math operator (so 0.6 becomes 1, 1.33 becomes 2, etc...).
  3. Use a Switch construct to take the rounded up number stored in the $Quarter variable and select the right month and day, always appending the current Year to the pre-determined Month/Day combination.

Checking $StartDate shows that no matter what was used for $Today's date, the correct first day of the corresponding calendar quarter was used. However... That Switch construct seemed like a little bit overkill (and I was hard coding the month) for something that should be simple, so I thought long and hard about how to streamline it further and came up with this replacement one-liner for the Switch construct:

 
$StartDate = ($Quarter * 3 - 2).ToString() + "/1/" + $Today.Year.ToString()

This code multiplies the rounded up Quarter number by 3 (so 1 becomes 3, 2 becomes 6, etc..), then subtracts 2 from it (so 3 becomes 1, 6 becomes 4, etc...), and then uses that number as the Month, still hard coding the day of "1" with forward slashes on both sides of it, and appends the current year.

This reduced the total number of lines down to 3. You could go a step further and try to cram it all on one line like the following, but please don't do that as it is a lot harder to read / unnecessarily uses two cmdlet calls for the same data / we aren't paying by the carriage return :) :

 
$StartDate = "$((([Math]::Ceiling((Get-Date).Month / 3)) * 3 - 2))/1/" + (Get-Date).Year.ToString()

Lastly I provided my colleague this additional code in case the maximum the query could go backwards in time was 90 days, so that the StartDate would be 90 days or the first day of the current quarter, which ever was more recent/closest to today:

 
$90Days = (Get-Date).AddDays(-90)
If ((Get-Date $StartDate) -lt $90Days) {
    $StartDate = $90Days.ToShortDateString()
}

When Eric integrated this code into his script, he came up with the following code (building on the code above) to determine the last day in the current calendar quarter:

 
$LastDay = [DateTime]::DaysInMonth([Int]$Today.Year.ToString(),[Int]($Quarter * 3))
$EndDate = ($Quarter * 3).ToString() + "/$LastDay/" + $Today.Year.ToString()

This code is quite clever as it uses the DateTime type cast, and tells it to calculate the days in the month for the "year, month". Since we want the last month in the quarter we multiply by 3 (so 1 becomes 3, 2 becomes 6, etc...), and the number of days returned is also the last day in the quarter. Very slick Eric. :)

Putting it all together you get this couple of lines to get the first and last days of the current quarter in PowerShell:

 
$Today = Get-Date
$Quarter = [Math]::Ceiling($Today.Month / 3)
$StartDate = ($Quarter * 3 - 2).ToString() + "/1/" + $Today.Year.ToString()
$LastDay = [DateTime]::DaysInMonth([Int]$Today.Year.ToString(),[Int]($Quarter * 3))
$EndDate = ($Quarter * 3).ToString() + "/$LastDay/" + $Today.Year.ToString()

Hopefully this is helpful to someone out there in the future if the never need to figure out the first and/or last days of a calendar quarter for any particular date (it doesn't have to be today - modify the first line to Get-Date a specific date).

Thanks!

Dan Sheehan

Senior Premier Field Engineer

Comments

  • Anonymous
    September 22, 2017
    IMO the string format of the resulting dates is a disadvantage. So I prefer:$Today = [datetime]::today$StartDate =Get-Date $Today -Month ([math]::ceiling($Today.Month/3)*3-2) -Day 1$EndDate = $StartDate.AddMonths(3).AddSeconds(-1)
    • Anonymous
      September 22, 2017
      The comment has been removed
  • Anonymous
    April 24, 2018
    This is the type of snippet everyone needs.