在PowerShell中搜索如何获取ISO 8601 Week of Year时,我偶然发现了this question for C#。
尽量不要使用PowerShell代码来解决这个问题,这里是我的Powershell端口。 (基于answer by user6887101)
我离开了这个“不被接受的”'如果有人想出一个更好的解决方案,有一段时间。
答案 0 :(得分:3)
如user6887101所述并详细解释here,伪算法是:
ISO 8601周以星期一开头,以星期日结束。
Sunday, January 1st XXXX
,请找到Thursday, December 29th XXXX-1
Monday, December 31st XXXX
,请找到Thursday, January 3rd XXXX+1
Year of the ISO 8601 Week
是包含Thursday found in step 1
的内容(例如:XXXX-1
或XXXX+1
)ISO 8601 Week number
是number of Thursdays
中的year 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
}
}
}
快速测试:
PS C:\> Get-Date | Get-ISO8601Week
Year WeekNumber WeekString DateString
---- ---------- ---------- ----------
2017 41 2017-W41 2017-10-11 Wednesday
在广泛的输入中测试正确的结果:
#<# 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
'============================================================='
}
#>
&#39;棘手&#39;日期引用@ 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
...........
#>
答案 1 :(得分:2)
聚会晚了一点,但是...只是要把这个答案留在这里,因为这个问题是我寻找解决方案的第一件事。有一种更简单的方法:
get-date -UFormat %V
OR
"{0:d1}" -f ($(Get-Culture).Calendar.GetWeekOfYear((Get-Date),[System.Globalization.CalendarWeekRule]::FirstFourDayWeek, [DayOfWeek]::Monday))
取决于是否要使用ISO8601。
答案 2 :(得分:0)
$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)
答案 3 :(得分:0)
对于纯Powershell: 文化和UICulture有问题 以文化的语言打印一周的第一天:
(Get-Culture).DateTimeFormat.DayNames[(Get-Culture).DateTimeFormat.FirstDayOfWeek.value__]
然后是周数不符合ISO8601标准的问题。 日期2012-12-31应该是第1周,但它给出了53。 因此,您将必须实施某种解决方案。
(Get-Culture).Calendar.GetWeekOfYear((Get-Date).AddDays(3*([int](Get-Date).DayOfWeek -in (1,2,3))), ((Get-Culture).DateTimeFormat.CalendarWeekRule), ((Get-Culture).DateTimeFormat.FirstDayOfWeek))
用于测试:
(Get-Culture).Calendar.GetWeekOfYear((Get-Date('2013-01-01')).AddDays(3*([int](Get-Date('2013-01-01')).DayOfWeek -in (1,2,3))), ((Get-Culture).DateTimeFormat.CalendarWeekRule), ((Get-Culture).DateTimeFormat.FirstDayOfWeek))
(Get-Culture).Calendar.GetWeekOfYear((Get-Date('2012-12-31')).AddDays(3*([int](Get-Date('2012-12-31')).DayOfWeek -in (1,2,3))), ((Get-Culture).DateTimeFormat.CalendarWeekRule), ((Get-Culture).DateTimeFormat.FirstDayOfWeek))
(Get-Culture).Calendar.GetWeekOfYear((Get-Date('2012-12-30')).AddDays(3*([int](Get-Date('2012-12-30')).DayOfWeek -in (1,2,3))), ((Get-Culture).DateTimeFormat.CalendarWeekRule), ((Get-Culture).DateTimeFormat.FirstDayOfWeek))
这些应该给出1,1,52(正确),而不是1,53,52(不正确)。 或(UICulture相关版本)
(Get-UICulture).Calendar.GetWeekOfYear((Get-Date).AddDays(3*([int](Get-Date).DayOfWeek -in (0,1,2))), ((Get-UICulture).DateTimeFormat.CalendarWeekRule), ((Get-UICulture).DateTimeFormat.FirstDayOfWeek))
用于测试:
(Get-UICulture).Calendar.GetWeekOfYear((Get-Date('2013-01-01')).AddDays(3*([int](Get-Date('2013-01-01')).DayOfWeek -in (0,1,2))), ((Get-UICulture).DateTimeFormat.CalendarWeekRule), ((Get-UICulture).DateTimeFormat.FirstDayOfWeek))
(Get-UICulture).Calendar.GetWeekOfYear((Get-Date('2012-12-31')).AddDays(3*([int](Get-Date('2012-12-31')).DayOfWeek -in (0,1,2))), ((Get-UICulture).DateTimeFormat.CalendarWeekRule), ((Get-UICulture).DateTimeFormat.FirstDayOfWeek))
(Get-UICulture).Calendar.GetWeekOfYear((Get-Date('2012-12-30')).AddDays(3*([int](Get-Date('2012-12-30')).DayOfWeek -in (0,1,2))), ((Get-UICulture).DateTimeFormat.CalendarWeekRule), ((Get-UICulture).DateTimeFormat.FirstDayOfWeek))
(Get-UICulture).Calendar.GetWeekOfYear((Get-Date('2012-12-29')).AddDays(3*([int](Get-Date('2012-12-29')).DayOfWeek -in (0,1,2))), ((Get-UICulture).DateTimeFormat.CalendarWeekRule), ((Get-UICulture).DateTimeFormat.FirstDayOfWeek))
这些应该给出1,1,1,52(正确),而不是1,53,53,52(不正确)。 因为开始的工作日是星期天。
您可以通过将3 *替换为0 *来测试错误的结果。
答案 4 :(得分:0)
荷兰文化。
我通过跳过星期天(因为它是 [int]0)并将其他天数添加/减去到星期四来解决它:
function Get-ISO8601Week([datetime]$DT = (Get-Date)) {
(Get-Culture).Calendar.GetWeekOfYear((Get-Date($DT)).AddDays(
<#
First create an integer(0/1) from the boolean,
"Is the integer DayOfWeek value greater than zero?".
Then Multiply it with 4 minus the integer DayOfWeek value.
This turns every day (except Sunday) into Thursday.
Then return the ISO8601 WeekNumber.
#>
[int](([int](Get-Date($DT)).DayOfWeek) -gt 0)*(4 - ([int](Get-Date($DT)).DayOfWeek) )
), ((Get-Culture).DateTimeFormat.CalendarWeekRule), ((Get-Culture).DateTimeFormat.FirstDayOfWeek))
}
Get-ISO8601Week('2013-01-01')
Get-ISO8601Week('2012-12-31')
Get-ISO8601Week('2012-12-30')
Get-ISO8601Week('2012-12-29')
这是一个错误修正!
答案 5 :(得分:0)
我想我找到了一个非常健壮的实现。
#ISO week
$date = [DateTime] '2014-12-29'
(Get-Culture).Calendar.GetWeekOfYear(($date).AddDays(-[Int] (($date).AddDays(-1)).DayOfWeek+3), 2, 1)
#ISO year
(Get-Culture).Calendar.GetYear(($date).AddDays(-[Int] (($date).AddDays(-1)).DayOfWeek+3))
这将计算一周中的星期四。 其他解决方案会错误地计算给定日期的第 53 周。