function Test-DayProperties {
<# MIT License
Copyright (c) 2017 Kirill Nikolaev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
#>
<#
.SYNOPSIS
Tests the given date against different conditions.
.DESCRIPTION
The function helps you to detect if today is the third Tuesday in a month, if the date belongs to some quarter, if today is the last day of a month etc.
.PARAMETER Date
The date object which you are testing. By default, the current date/time.
.PARAMETER DayOfWeek
Use to test if the day is the defined day in a week (Mon, Tue, Wed etc).
.PARAMETER NumberInMonth
Use to detect if the day is the specified number of the day type defined in the DayOfWeek parameter.
.PARAMETER EndOfMonth
Use to detect if the given day is the last day of the month.
.PARAMETER Quarter
Use to detect if the given day is belongs to the specified quarter.
.PARAMETER QuarterType
Use to detect if the given day is the start or the end of the specified quarter.
.PARAMETER Last
Use to detect if the given day is the last day of some kind in the given month. If the DayOfWeek parameter is omitted, the kind of day is extracted from the Date parameter, otherwise — DayOfWeek is used.
.EXAMPLE
Test-DayProperties -DayOfWeek 2 -NumberInMonth 2
Tests if the current day is the second Tuesday in this month.
.EXAMPLE
Test-DayProperties -Date $Date -DayOfWeek 7 -Last
Tests if the date in the $Date object is the last Sunday in the month.
.EXAMPLE
Test-DayProperties -Last
Tests if today is the last day of its kind in the month.
.EXAMPLE
Test-DayProperties -EndOfMonth
Tests if today is the last day of the month.
.EXAMPLE
Test-DayProperties -Date $Date -Quarter 3 -QuarterType End
Tests if the date in the $Date object is the end (the last day) of the 3rd quarter.
.EXAMPLE
Test-DayProperties -QuarterType Start
Tests if today is the beginning of a quarter.
.EXAMPLE
Test-DayProperties $Date -Quarter 1
Tests if the date in the $Date object belonngs to the 1st quarter.
.INPUTS
[DateTime]
.OUTPUTS
[boolean]
.NOTES
Author: Kirill Nikolaev
Twitter: @exchange12rocks
.LINK
https://exchange12rocks.org/2017/05/29/function-to-test-a-date-against-different-conditions
.LINK
https://github.com/exchange12rocks/PS/tree/master/Test-DayProperties
#>
#Requires -Version 3.0
[CmdletBinding(
DefaultParametersetName='Default'
)]
[OutputType([boolean])]
Param (
[Parameter(ParameterSetName='Default', Position = 0)]
[Parameter(ParameterSetName='Quarter', Position = 0)]
[Parameter(ParameterSetName='QuarterType', Position = 0)]
[Parameter(ParameterSetName='EndOfMonth', Position = 0)]
[Parameter(ParameterSetName='Last', Position = 0)]
[ValidateNotNullorEmpty()]
[DateTime]$Date = (Get-Date),
[Parameter(ParameterSetName='Default', Mandatory)]
[Parameter(ParameterSetName='Last')]
[ValidateRange(1,7)]
[int]$DayOfWeek,
[Parameter(ParameterSetName='Default', Mandatory)]
[ValidateRange(1,5)] # It's impossible to have more that 5 weeks in a month (on Earth)
[int]$NumberInMonth,
[Parameter(ParameterSetName='EndOfMonth')]
[switch]$EndOfMonth,
[Parameter(ParameterSetName='Quarter', Mandatory)]
[Parameter(ParameterSetName='QuarterType')]
[ValidateRange(1,4)]
[int]$Quarter,
[Parameter(ParameterSetName='QuarterType', Mandatory)]
[ValidateSet('Start','End')]
[string]$QuarterType,
[Parameter(ParameterSetName='Last', Mandatory)]
[switch]$Last
)
function GetLastDateOfCurrentMonth {
Param (
[ValidateNotNullorEmpty()]
[DateTime]$Date = (Get-Date)
)
$result = $false
if ($Date.Month -in @(1, 3, 5, 7, 8, 10, 12)) {
$result = New-Object -TypeName DateTime -ArgumentList @($Date.Year, $Date.Month, 31)
}
elseif ($Date.Month -in @(4, 6, 9, 11)) {
$result = New-Object -TypeName DateTime -ArgumentList @($Date.Year, $Date.Month, 30)
}
else { #February
try {
$result = New-Object -TypeName DateTime -ArgumentList @($Date.Year, $Date.Month, 29)
}
catch {
if ($Error[0].Exception.InnerException.HResult -eq -2146233086) {
$result = New-Object -TypeName DateTime -ArgumentList @($Date.Year, $Date.Month, 28)
}
}
}
return $result
}
function GetDotNETDayOfWeek {
Param (
[ValidateRange(1,7)]
[int]$DayOfWeek
)
if ($DayOfWeek -eq 7) {
return 0
}
else {
return $DayOfWeek
}
}
$result = $false
switch ($PSCmdlet.ParameterSetName) {
'QuarterType' {
if ($QuarterType -eq 'Start') {
if ($Date.Day -eq 1 -and $Date.Month -in (1,4,7,10)) {
$result = $true
if ($Quarter) {
if ($Date.Month -ne (3*$Quarter-2)) {
$result = $false
}
}
}
}
elseif ($QuarterType -eq 'End') {
if (($Date.Month -in (3,6,9,12)) -and $Date.Day -eq ((GetLastDateOfCurrentMonth -Date $Date).Day)) {
$result = $true
}
}
}
'Quarter' {
if ($Date.Month -in ((3*$Quarter-2)..(3*$Quarter))) {
$result = $true
}
}
'EndOfMonth' {
if ($Date -eq (GetLastDateOfCurrentMonth -Date $Date)) {
$result = $true
}
}
'Last' {
$LastDateOfCurrentMonth = GetLastDateOfCurrentMonth -Date $Date
$StartOfLast7Days = $LastDateOfCurrentMonth.AddDays(-6)
if (!$DayOfWeek) {
if ($Date -ge $StartOfLast7Days -and $Date -le $LastDateOfCurrentMonth) {
$result = $true
}
}
elseif ($Date.DayOfWeek.value__ -eq (GetDotNETDayOfWeek -DayOfWeek $DayOfWeek) -and $Date -ge $StartOfLast7Days -and $Date -le $LastDateOfCurrentMonth) {
$result = $true
}
}
'Default' {
$DaysToSubstract = (7*($NumberInMonth-1))
if ((New-TimeSpan -Days $DaysToSubstract).Ticks -le $Date.Ticks) {
if ($Date.DayOfWeek.value__ -eq (GetDotNETDayOfWeek -DayOfWeek $DayOfWeek) -and $Date.AddDays(-$DaysToSubstract).Month -eq $Date.Month -and $Date.Day -le (7*$NumberInMonth)) {
$result = $true
}
}
}
Default {
$result = $false
}
}
return $result
}