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 (2)

  1. LotPings says:

    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)

    1. The string is only a disadvantage if your input can handle a Date/Time object from PowerShell. If you are going to perform a remote SQL query for instance, a string is the preferred method so you can control what is passed into SQL as it doesn’t understand PowerShell objects.

      Also you need to keep in mind code posted for others to consume needs to be easily understood and recycled. Your example of Today being set to “[DateTime]::Today” is no different than my “Get-Date”, but isn’t using a standard PowerShell cmdlet which should always be preferred unless there is a performance difference. Also your StartDate is attempting to put everything into one line which I discourage against when trying to teach others how to use PowerShell as we aren’t paying by the carriage return. 🙂

      Your EndDate example may prove to be a more efficient single line versus the DaysInMonth trick Eric came up with (he admittedly had it all in one line but I broke it out for better readability/understanding).

Skip to main content