# encoding: ascii
# api: powershell
# title: IsoDates.psm1
# description: A handful of functions for returning IS0-8601 formatted dates and parsing them. All functions work (even in the pipeline) in both PowerShell 1 and 2.
# version: 2.0
# type: function
# author: Joel Bennett
# license: GPL, MS-RL, MS-PL, or BSD
# function: Get-ISODate
# x-poshcode-id: 966
# x-archived: 2016-04-22T18:46:31
# x-published: 2009-03-19T22:14:00
#
#
#requires -version 1.0
# or version 2.0, obviously
## ISO 8601 Dates
########################################################################
## Copyright (c) Joel Bennett, 2009
## Free for use under GPL, MS-RL, MS-PL, or BSD license. Your choice.
function Get-ISODate {
#.Synopsis
# Get the components of an ISO 8601 date: year, week number, day of week
#.Description
# For any given date you get an array of year, week, day that you can use
# as part of a string format....
#.Parameter Date
# The date you want to analyze. Accepts dates on the pipeline
Param([DateTime]$date=$(Get-Date))
Process {
if($_){$date=$_}
## Get Jan 1st of that year
$startYear = Get-Date -Date $date -Month 1 -Day 1
## Get Dec 31st of that year
$endYear = Get-Date -Date $date -Month 12 -Day 31
## ISO 8601 weeks are Monday-Sunday, with days marked 1-7
## But .Net's DayOfWeek enum is 0 for Sunday through 6 for saturday
$dayOfWeek = @(7,1,2,3,4,5,6)[$date.DayOfWeek]
$lastofWeek = @(7,1,2,3,4,5,6)[$endYear.DayOfWeek]
## By definition: the first week of a year is the one which
## includes the first Thursday, and thus, January 4th
$adjust = @(6,7,8,9,10,4,5)[$startYear.DayOfWeek]
switch([Math]::Floor((($date.Subtract($startYear).Days + $adjust)/7)))
{
0 {
## Return weeknumber of dec 31st of the previous year
## But return THIS dayOfWeek
Write-Output @(
@(Get-ISODate $startYear.AddDays(-1))[0,1] + @(,$dayOfWeek))
}
53 {
## If dec 31st falls before thursday it is week 01 of next year
if ($lastofWeek -lt 4) {
Write-Output @(($date.Year + 1), 1, $dayOfWeek)
} else {
Write-Output @($date.Year, $_, $dayOfWeek)
}
}
default {
Write-Output @($date.Year, $_, $dayOfWeek)
}
}
}
}
function Get-ISOWeekOfYear {
#.Synopsis
# Get the correct (according to ISO 8601) week number
#.Description
# For any given date you get the week of the year, according to ISO8610
#.Parameter Date
# The date you want to analyze. Accepts dates on the pipeline
Param([DateTime]$date=$(Get-Date))
Process {
if($_){$date=$_}
@(Get-ISODate $date)[1]
}
}
function Get-ISOYear {
#.Synopsis
# Get the correct (according to ISO 8601) year number
#.Description
# For any given date you get the year number, according to ISO8610 ...
# for some days at the begining or end of year, it reports the previous
# or the next year (because ISO defines those days as part of the first
# or last week of the adjacent year).
#.Parameter Date
# The date you want to analyze. Accepts dates on the pipeline
Param([DateTime]$date=$(Get-Date))
Process {
if($_){$date=$_}
@(Get-ISODate $date)[0]
}
}
function Get-ISODayOfWeek {
#.Synopsis
# Get the correct (according to ISO 8601) day of the week
#.Description
# For any given date you get the day of the week, according to ISO8610
#.Parameter Date
# The date you want to analyze. Accepts dates on the pipeline
Param([DateTime]$date=$(Get-Date))
Process {
if($_){$date=$_}
@(7,1,2,3,4,5,6)[$date.DayOfWeek]
}
}
function Get-ISODateString {
#.Synopsis
# Get the correctly formatted (according to ISO 8601) date string
#.Description
# For any given date you get the date string, according to ISO8610,
# like: 2009-W12-4 for Thursday, March 19th, 2009
#.Parameter Date
# The date you want to analyze. Accepts dates on the pipeline
Param([DateTime]$date=$(Get-Date))
Process {
if($_){$date=$_}
"{0}-W{1:00}-{2}" -f @(Get-ISODate $date)
}
}
function ConvertFrom-ISODateString {
#.Synopsis
# Parses ISO 8601 Date strings in the format: 2009-W12-4 to DateTime
#.Description
# Allows converting ISO-formated date strings back into actual objects
#.Parameter Date
# An ISO8601 date, like:
# 2009-W12-4 for Thursday, March 19th, 2009
# 1999-W52-6 for Saturday, January 1st, 2000
# 2000-W01-1 for Monday, January 3rd, 2000
Param([string]$date)
Process {
if($_){$date=$_}
if($date -notmatch "\d{4}-W\d{2}-\d") {
Write-Error "The string is not an ISO 8601 formatted date string"
}
$ofs = ""
$year = [int]"$($date[0..3])"
$week = [int]"$($date[6..7])"
$day = [int]"$($date[9])"
$firstOfYear = Get-Date -year $year -day 1 -month 1
$days = 7*$week - ((Get-ISODayOfWeek $firstOfYear) - $day)
$result = $firstOfYear.AddDays( $days )
if(($result.Year -ge $year) -and ((Get-ISODayOfWeek $firstOfYear) -le 4) ) {
return $firstOfYear.AddDays( ($days - 7) )
} else {
return $result
}
}
}