Get the ISO 8601 Week of Year of a given date in Powershell Get the ISO 8601 Week of Year of a given date in Powershell powershell powershell

Get the ISO 8601 Week of Year of a given date in Powershell


As mentioned by user6887101 and explained in detail here, the pseudo-algorithm is:

An ISO 8601 Week starts with Monday and ends with Sunday.

  1. For any given date, find the Thursday from the same week as the givendate. E.g.:
    • If original date is Sunday, January 1st XXXX find the Thursday, December 29th XXXX-1
    • If original date is Monday, December 31st XXXX find the Thursday, January 3rd XXXX+1
  2. The Year of the ISO 8601 Week is the one containing the Thursday found in step 1 (e.g.: XXXX-1 or XXXX+1)
  3. The ISO 8601 Week number is the number of Thursdays in the year from step 2 (up to and including the found Thursday itself)
function Get-ISO8601Week (){# Adapted from https://stackoverflow.com/a/43736741/444172  [CmdletBinding()]  param(    [Parameter(      ValueFromPipeline                =  $true,      ValueFromPipelinebyPropertyName  =  $true    )]                                           [datetime]  $DateTime  )  process {    foreach ($_DateTime in $DateTime) {      $_ResultObject   =  [pscustomobject]  @{        Year           =  $null        WeekNumber     =  $null        WeekString     =  $null        DateString     =  $_DateTime.ToString('yyyy-MM-dd   dddd')      }      $_DayOfWeek      =  $_DateTime.DayOfWeek.value__      # In the underlying object, Sunday is always 0 (Monday = 1, ..., Saturday = 6) irrespective of the FirstDayOfWeek settings (Sunday/Monday)      # Since ISO 8601 week date (https://en.wikipedia.org/wiki/ISO_week_date) is Monday-based, flipping Sunday to 7 and switching to one-based numbering.      if ($_DayOfWeek  -eq  0) {        $_DayOfWeek =    7      }      # Find the Thursday from this week:      #     E.g.: If original date is a Sunday, January 1st     , will find     Thursday, December 29th     from the previous year.      #     E.g.: If original date is a Monday, December 31st   , will find     Thursday, January 3rd       from the next year.      $_DateTime                 =  $_DateTime.AddDays((4  -  $_DayOfWeek))      # The above Thursday it's the Nth Thursday from it's own year, wich is also the ISO 8601 Week Number      $_ResultObject.WeekNumber  =  [math]::Ceiling($_DateTime.DayOfYear    /   7)      $_ResultObject.Year        =  $_DateTime.Year      # The format requires the ISO week-numbering year and numbers are zero-left-padded (https://en.wikipedia.org/wiki/ISO_8601#General_principles)      # It's also easier to debug this way :)      $_ResultObject.WeekString  =  "$($_DateTime.Year)-W$("$($_ResultObject.WeekNumber)".PadLeft(2,  '0'))"      Write-Output                  $_ResultObject    }  }}

Quick test:

PS C:\>  Get-Date  |  Get-ISO8601WeekYear WeekNumber WeekString DateString---- ---------- ---------- ----------2017         41 2017-W41   2017-10-11   Wednesday

Test correct results accross a wide range of inputs:

#<# Test Get-ISO8601Week (You can manually check accuracy @ https://planetcalc.com/1252/)#   Tested on $PSVersionTable.PSVersion :#       5.1.15063.502    "Week starts on:    $([System.Globalization.DateTimeFormatInfo]::CurrentInfo.FirstDayOfWeek)"#   Test dates from 2000-01-01 (730119) to 2020-12-31 (737789)#   To get the 'serial day number' for a given date, use:#   (Get-Date   -Date '2020-12-31').Ticks   /   [timespan]::TicksPerDay    $WeekOfYearObjectGroupList      =   730119..737789  |   ForEach-Object  -Process {[datetime]::new(($_ * [timespan]::TicksPerDay))}  |   Get-ISO8601Week |   Group-Object    -Property 'Year'    '============================================================='    foreach ($WeekOfYearObjectGroup in  $WeekOfYearObjectGroupList) {        $WeekOfYearObjectGroup.Group  |  Where-Object  {$_.WeekNumber  -lt  1       }  |  Format-Table  -AutoSize        $WeekOfYearObjectGroup.Group  |  Where-Object  {$_.WeekNumber  -in  1..2    }  |  Format-Table  -AutoSize        '...........'        $WeekOfYearObjectGroup.Group  |  Where-Object  {$_.WeekNumber  -in  52..53  }  |  Format-Table  -AutoSize        $WeekOfYearObjectGroup.Group  |  Where-Object  {$_.WeekNumber  -gt  53      }  |  Format-Table  -AutoSize    '============================================================='    }#>

Sample of 'tricky' dates referenced @ MSDN
You can manually check accuracy @ https://planetcalc.com/1252/

<#  Sample of 'tricky' dates referenced @ https://blogs.msdn.microsoft.com/shawnste/2006/01/24/iso-8601-week-of-year-format-in-microsoft-net/    ...........    2004         52 2004-W52   2004-12-26   Sunday    2004         53 2004-W53   2004-12-27   Monday    2004         53 2004-W53   2004-12-28   Tuesday    2004         53 2004-W53   2004-12-29   Wednesday    2004         53 2004-W53   2004-12-30   Thursday    2004         53 2004-W53   2004-12-31   Friday    2004         53 2004-W53   2005-01-01   Saturday    2004         53 2004-W53   2005-01-02   Sunday    =============================================================    2005          1 2005-W01   2005-01-03   Monday    2005          1 2005-W01   2005-01-04   Tuesday    2005          1 2005-W01   2005-01-05   Wednesday    2005          1 2005-W01   2005-01-06   Thursday    2005          1 2005-W01   2005-01-07   Friday    2005          1 2005-W01   2005-01-08   Saturday    2005          1 2005-W01   2005-01-09   Sunday    2005          2 2005-W02   2005-01-10   Monday    ...........#>


A little late to the party, but... just going to leave this answer here since this question was the first thing i stumbled upon when looking for a solution to this. There's a much easier way:

get-date -UFormat %V

OR

"{0:d1}" -f ($(Get-Culture).Calendar.GetWeekOfYear((Get-Date),[System.Globalization.CalendarWeekRule]::FirstFourDayWeek, [DayOfWeek]::Monday))

Depending on if you want ISO8601 or not.


$checkdate = Get-Date -date "2007-12-31"$dow=[int]($checkdate).dayofweek# if the day of week is before Thurs (Mon-Wed) add 3 since Thursday is the critical# day for determining when the ISO week starts.if ($dow -match "[1-3]") {$checkdate.addDays(3)}# Return the ISO week number$(Get-Culture).Calendar.GetWeekOfYear(($checkdate),[System.Globalization.CalendarWeekRule]::FirstFourDayWeek, [DayOfWeek]::Monday)

From https://ss64.com/ps/get-date.html