Skip to content

Instantly share code, notes, and snippets.

@exactmike
Created February 11, 2019 23:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save exactmike/517c5005319952c785a191c6143ca467 to your computer and use it in GitHub Desktop.
Save exactmike/517c5005319952c785a191c6143ca467 to your computer and use it in GitHub Desktop.
Get-DateSeries
<#
.SYNOPSIS
Given a start date, gets a series of dates for a specified interval and units and limit
.DESCRIPTION
Given a start date, Gets a series of dates for a specified interval (like 7), and units (like days), and limit (the number of results you want in the series).
For example, You can get every 14th day from this Friday for the next 10 sets of 14 days.
Or, you can get every 4th minute for the next 400 minutes by specifying limit 100, units minutes, interval 4.
.EXAMPLE
$vday = Get-Date -Year 2019 -Month 2 -Day 14 -Hour 12 -Minute 0 -Second 0
Get-DateSeries -Start $vday -Interval 14 -Units Days -Limit 10
Thursday, February 14, 2019 12:00:00 PM
Thursday, February 28, 2019 12:00:00 PM
Thursday, March 14, 2019 12:00:00 PM
Thursday, March 28, 2019 12:00:00 PM
Thursday, April 11, 2019 12:00:00 PM
Thursday, April 25, 2019 12:00:00 PM
Thursday, May 9, 2019 12:00:00 PM
Thursday, May 23, 2019 12:00:00 PM
Thursday, June 6, 2019 12:00:00 PM
Thursday, June 20, 2019 12:00:00 PM
NOTE:Date input and output format results may differ depending on your Culture settings.
From (and including) the Start, gets a datetime object for the 10 dates with each date being 14 days apart.
.EXAMPLE
$vday = Get-Date -Year 2019 -Month 2 -Day 14 -Hour 12 -Minute 0 -Second 0
Get-DateSeries -Start $vday -Interval 14 -Units Days -Limit 10 -SkipStart
Thursday, February 28, 2019 12:00:00 PM
Thursday, March 14, 2019 12:00:00 PM
Thursday, March 28, 2019 12:00:00 PM
Thursday, April 11, 2019 12:00:00 PM
Thursday, April 25, 2019 12:00:00 PM
Thursday, May 9, 2019 12:00:00 PM
Thursday, May 23, 2019 12:00:00 PM
Thursday, June 6, 2019 12:00:00 PM
Thursday, June 20, 2019 12:00:00 PM
Thursday, July 4, 2019 12:00:00 PM
NOTE:Date input and output format results may differ depending on your Culture settings.
From the Start, gets a datetime object for the next 10 dates with each date being 14 days apart. -SkipStart excludes the start date from the result set.
.EXAMPLE
Get-DateSeries -Start '2019-02-14 11:30:00' -Interval 5 -Units Minutes -Limit 10
Thursday, February 14, 2019 11:30:00 AM
Thursday, February 14, 2019 11:35:00 AM
Thursday, February 14, 2019 11:40:00 AM
Thursday, February 14, 2019 11:45:00 AM
Thursday, February 14, 2019 11:50:00 AM
Thursday, February 14, 2019 11:55:00 AM
Thursday, February 14, 2019 12:00:00 PM
Thursday, February 14, 2019 12:05:00 PM
Thursday, February 14, 2019 12:10:00 PM
Thursday, February 14, 2019 12:15:00 PM
NOTE:Date input and output format results may differ depending on your Culture settings.
Gets a date time object for every 5 minutes from 11:30:00 through 12:15:00
.INPUTS
DateTime
.OUTPUTS
DateTime
#>
function Get-DateSeries
{
[CmdletBinding()]
[Alias('gds')]
[OutputType([DateTime[]])]
Param
(
# Specifies a DateTime object from which to start the series calculation. Values that can be dynamically converted by PowerShell to DateTime are also acceptable. Is included in the series output unless -SkipStart is specified.
[Parameter(
Mandatory,
Position = 0,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true
)]
[datetime]
$Start,
# Specifies the value to use as the interval between datetime objects in the series in the Units specified in -Units.
[Parameter(
Mandatory,
Position = 1
)]
[ValidateRange(1, [int]::MaxValue)]
[int]
$Interval,
# Specifies the value to use for the interval of time Units to create the series.
[Parameter(
Mandatory,
Position = 2
)]
[ValidateSet('Milliseconds','Seconds','Minutes','Hours','Days','Weeks','Months','Years')]
[string]
$Units,
# Specifies how many results to include in the series
[Parameter(
Mandatory,
Position = 3
)]
[ValidateRange(1,[int]::MaxValue)]
[Int]
$Limit
,
# Specifies to NOT include the Start datetime in the series. Otherwise, the start datetime is included.
[Parameter(
Position = 4
)]
[switch]
$SkipStart
)
begin
{
}
process
{
$iteration = 0
if ($true -ne $SkipStart)
{
$Start
$iteration++
}
$outputDate = $Start
while ($iteration -lt $Limit) {
$iteration++
$nextDate = $(
Switch ($Units)
{
'Milliseconds'
{
$outputDate.AddMilliseconds($Interval)
}
'Seconds'
{
$outputDate.AddSeconds($Interval)
}
'Minutes'
{
$outputDate.AddMinutes($Interval)
}
'Hours'
{
$outputDate.AddHours($Interval)
}
'Days'
{
$outputDate.AddDays($Interval)
}
'Weeks'
{
$intervalInDays = $Interval * 7
$outputDate.AddDays($intervalInDays)
}
'Months'
{
$outputDate.AddMonths($Interval)
}
'Years'
{
$outputDate.AddYears($Interval)
}
}
)
$nextDate
$outputDate = $nextDate
}
}
end
{
}
}
$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "")
Describe "$CommandName Unit Tests" -Tag 'UnitTests' {
Context "Validate parameters" {
$defaultParamCount = 11
[object[]]$params = (Get-ChildItem "function:\$CommandName").Parameters.Keys
$knownParameters = 'Start','Interval','Units','Limit','SkipStart'
$paramCount = $knownParameters.Count
It "Should contain specific parameters" {
( (Compare-Object -ReferenceObject $knownParameters -DifferenceObject $params -IncludeEqual | Where-Object SideIndicator -eq "==").Count ) | Should Be $paramCount
}
It "Should only contain $paramCount parameters" {
$params.Count - $defaultParamCount | Should Be $paramCount
}
}
}
Describe "$commandname Integration Tests" -Tags "IntegrationTests" {
BeforeAll {
$vday = Get-Date -Year 2019 -Month 2 -Day 14 -Hour 12 -Minute 0 -Second 0
}
AfterAll {
}
Context "Validates Input" {
It "Binds only values that are dateTime to the Start parameter" {
{Get-DateSeries -Start 'tomorrow' -Interval 3 -Units Days -Limit 3 } | Should Throw
{Get-DateSeries -Start '2019-02-14' -Interval 3 -Units Days -Limit 3} | Should NOT Throw
{Get-DateSeries -Start '2019-02-14 11:30:00' -Interval 5 -Units Minutes -Limit 10} | Should NOT Throw
{Get-DateSeries -Start $vday -Interval 3 -Units Days -Limit 3} | Should NOT Throw
}
It "Binds only values that are integers to the Interval parameter" {
{Get-DateSeries -Start $vday -Interval 4 -Units Days -Limit 3} | Should NOT Throw
{Get-DateSeries -Start $vday -Interval 'four' -Units Days -Limit 3} | Should Throw
}
It "Binds only values that are in the valid set to the Units parameter" {
{Get-DateSeries -Start $vday -Interval 4 -Units Days -Limit 3} | Should NOT Throw
{Get-DateSeries -Start $vday -Interval 4 -Units 'Decades' -Limit 3} | Should Throw
}
It "Binds only values that are integers in the ValidateRange to the Limit parameter" {
{Get-DateSeries -Start $vday -Interval 4 -Units Days -Limit 3} | Should NOT Throw
{Get-DateSeries -Start $vday -Interval 2 -Units Days -Limit 'five'} | Should Throw
{Get-DateSeries -Start $vday -Interval 2 -Units Days -Limit 0} | Should Throw
}
}
Context "Produces Expected Output" {
It "Produces the expected number of results" {
(Get-DateSeries -Start $vday -Interval 4 -Units Days -Limit 5).count | Should Be 5
(Get-DateSeries -Start $vday -Interval 2 -Units Days -Limit 1 -SkipStart).count | Should Be 1
}
$TestCases = @(
@{
Interval = 1
Units = 'Milliseconds'
}
@{
Interval = 5
Units = 'Milliseconds'
}
@{
Interval = 1
Units = 'Seconds'
}
@{
Interval = 5
Units = 'Seconds'
}
@{
Interval = 1
Units = 'Minutes'
}
@{
Interval = 5
Units = 'Minutes'
}
@{
Interval = 1
Units = 'Hours'
}
@{
Interval = 5
Units = 'Hours'
}
@{
Interval = 1
Units = 'Days'
}
@{
Interval = 5
Units = 'Days'
}
)
It -TestCases $TestCases "Produces the expected intervals with built-in datetime units" {
param($Interval,$Units)
$results = Get-DateSeries -Start $vday -Interval $Interval -Units $Units -Limit 2
$($results[1]-$results[0]).$('Total'+ $Units) | Should Be $Interval
}
$TestCases = @(
@{
Interval = 1
Units = 'Weeks'
}
@{
Interval = 5
Units = 'Weeks'
}
@{
Interval = 1
Units = 'Years'
}
@{
Interval = 5
Units = 'Years'
}
)
It -TestCases $TestCases "Produces the expected intervals with additional Units" {
param($Interval,$Units)
$results = Get-DateSeries -Start $vday -Interval $Interval -Units $Units -Limit 2
switch ($Units)
{
'Years'
{
switch ($Interval)
{
{$_ -lt 4}
{
$comparison = @($(365*$Interval);$(365*$interval) + 1)
}
{$_ -eq 4}
{
$comparison = @($(365*$interval)+1)
}
{$_ -gt 4}
{
if ($interval%4 -eq 0)
{$add = $Interval/4}
else
{$add = [math]::Truncate($($interval/4))}
$base = $Interval * 365
$comparison = @($($base + $add);$($base + $add + 1))
}
}
$($results[1]-$results[0]).TotalDays | Should BeIn $comparison
}
'Weeks'
{
$comparison = $interval * 7
$($results[1]-$results[0]).TotalDays | Should Be $comparison
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment