在 Powershell 中获取给定日期的 ISO 8601 年周

Pet*_*ria 3 powershell datetime date iso8601

在搜索如何在 PowerShell 中获取ISO 8601 Week of Year时,我偶然发现了 C# 的这个问题

尽量不要用 PowerShell 代码来解决这个问题,下面是我的 Powershell 端口。(基于user6887101回答

如果有人想出更好的解决方案,我会将这个“不接受”保留一段时间。

Pet*_*ria 6

正如user6887101所提到并在此处详细解释的,伪算法是:

与ISO 8601星期开始的星期一和结束与周日

  1. 对于任何给定日期,查找与给定日期同一周的星期四。例如:
    • 如果原始日期是Sunday, January 1st XXXX找到Thursday, December 29th XXXX-1
    • 如果原始日期是Monday, December 31st XXXX找到Thursday, January 3rd XXXX+1
  2. TheYear of the ISO 8601 Week是包含Thursday found in step 1(eg: XXXX-1or XXXX+1)
  3. ISO 8601 Week numbernumber of Thursdaysyear from step 2(直至并包括发现周四本身)
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
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

快速测试:

PS C:\>  Get-Date  |  Get-ISO8601Week

Year WeekNumber WeekString DateString
---- ---------- ---------- ----------
2017         41 2017-W41   2017-10-11   Wednesday
Run Code Online (Sandbox Code Playgroud)

在广泛的输入范围内测试正确的结果:

#<# 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
    '============================================================='
    }
#>
Run Code Online (Sandbox Code Playgroud)

引用“棘手”日期@样本MSDN
可以手动检查精度@ 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
    ...........
#>
Run Code Online (Sandbox Code Playgroud)


Ins*_*iac 6

聚会有点晚了,但是......只是想在这里留下这个答案,因为这个问题是我在寻找解决方案时偶然发现的第一件事。有一个更简单的方法:

get-date -UFormat %V

或者

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

取决于您是否想要 ISO8601。