From 6bd70bc2d065918c03228f54befc3ed8cf1bfc59 Mon Sep 17 00:00:00 2001 From: Ilya Date: Tue, 10 Apr 2018 08:13:19 +0400 Subject: [PATCH] Some fixes in Get-Date -UFormat (#6542) * Use UTC datetime in Get-Date -UFormat %s Fix %l output from 0..11 to 1..12 Fix %V using Gregorian calendar * Use a workaround for ISO 8601 week of year (uformat %V) --- .../commands/utility/GetDateCommand.cs | 33 +++++++++++++-- .../Get-Date.Tests.ps1 | 40 +++++++++++++++++-- 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs index 0ce4e3f873..7d188a2a10 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs @@ -393,7 +393,7 @@ namespace Microsoft.PowerShell.Commands break; case 'l': - sb.Append(StringUtil.Format("{0,2:0}", dateTime.Hour%12)); + sb.Append("{0,2:%h}"); break; case 'M': @@ -425,7 +425,7 @@ namespace Microsoft.PowerShell.Commands break; case 's': - sb.Append(StringUtil.Format("{0:0}", dateTime.Subtract(epoch).TotalSeconds)); + sb.Append(StringUtil.Format("{0:0}", dateTime.ToUniversalTime().Subtract(epoch).TotalSeconds)); break; case 'T': @@ -449,7 +449,34 @@ namespace Microsoft.PowerShell.Commands break; case 'V': - sb.Append((dateTime.DayOfYear / 7) + 1); + // .Net Core doesn't implement ISO 8601. + // So we use workaround from https://blogs.msdn.microsoft.com/shawnste/2006/01/24/iso-8601-week-of-year-format-in-microsoft-net/ + // with corrections from comments + + // Culture doesn't matter since we specify start day of week + var calender = CultureInfo.InvariantCulture.Calendar; + var day = calender.GetDayOfWeek(dateTime); + var normalizedDatetime = dateTime; + + switch (day) + { + case DayOfWeek.Monday: + case DayOfWeek.Tuesday: + case DayOfWeek.Wednesday: + normalizedDatetime = dateTime.AddDays(3); + break; + + case DayOfWeek.Friday: + case DayOfWeek.Saturday: + case DayOfWeek.Sunday: + normalizedDatetime = dateTime.AddDays(-3); + break; + } + + // FirstFourDayWeek and DayOfWeek.Monday is from ISO 8601 + sb.Append(StringUtil.Format("{0:00}",calender.GetWeekOfYear(normalizedDatetime, + CalendarWeekRule.FirstFourDayWeek, + DayOfWeek.Monday))); break; case 'G': diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Date.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Date.Tests.ps1 index 1f6d5c16c1..b5e448277a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Date.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Date.Tests.ps1 @@ -23,8 +23,13 @@ Describe "Get-Date DRT Unit Tests" -Tags "CI" { Get-date -Date:"Jan 1, 2020" -Format:"MMM-dd-yy" | Should -Be "Jan-01-20" } - It "using -uformat produces the correct output" { - Get-date -Date:"Jan 1, 2020" -UFormat:"%s" | Should -Be "1577836800" + It "using -uformat %s produces the correct output" { + $seconds = Get-date -Date:"Jan 1, 2020Z" -UFormat:"%s" + + $seconds | Should -Be "1577836800" + if ($isLinux) { + $seconds | Should -Be (date --date='01/01/2020 UTC' +%s) + } } It "using -uformat 'ymdH' produces the correct output" { @@ -32,11 +37,38 @@ Describe "Get-Date DRT Unit Tests" -Tags "CI" { } It "using -uformat 'aAbBcCdDehHIkljmMpr' produces the correct output" { - Get-date -Date 1/1/0030 -uformat %a%A%b%B%c%C%d%D%e%h%H%I%k%l%j%m%M%p%r | Should -Be "TueTuesdayJanJanuaryTue 01 Jan 0030 00:00:0000101/01/30 1Jan0012 0 00010100AM12:00:00 AM" + Get-date -Date 1/1/0030 -uformat "%a%A%b%B%c%C%d%D%e%h%H%I%k%l%j%m%M%p%r" | Should -Be "TueTuesdayJanJanuaryTue 01 Jan 0030 00:00:0000101/01/30 1Jan0012 0120010100AM12:00:00 AM" } It "using -uformat 'sStTuUVwWxXyYZ' produces the correct output" { - Get-date -Date 1/1/0030 -uformat %s%S%T%u%U%V%w%W%x%X%y%Y%% | Should -Be "-612204480000000:00:002012001/01/3000:00:00300030%" + Get-date -Date 1/1/0030 -uformat %S%T%u%U%w%W%x%X%y%Y%% | Should -Be "0000:00:00202001/01/3000:00:00300030%" + } + + # The 'week of year' test cases is from https://en.wikipedia.org/wiki/ISO_week_date + It "using -uformat 'V' produces the correct output" -TestCases @( + @{date="2005-01-01"; week = "53"}, + @{date="2005-01-02"; week = "53"}, + @{date="2005-12-31"; week = "52"}, + @{date="2006-01-01"; week = "52"}, + @{date="2006-01-02"; week = "01"}, + @{date="2006-12-31"; week = "52"}, + @{date="2007-01-01"; week = "01"}, + @{date="2007-12-30"; week = "52"}, + @{date="2007-12-31"; week = "01"}, + @{date="2008-01-01"; week = "01"}, + @{date="2008-12-28"; week = "52"}, + @{date="2008-12-29"; week = "01"}, + @{date="2008-12-30"; week = "01"}, + @{date="2008-12-31"; week = "01"}, + @{date="2009-01-01"; week = "01"}, + @{date="2009-12-31"; week = "53"}, + @{date="2010-01-01"; week = "53"}, + @{date="2010-01-02"; week = "53"}, + @{date="2010-01-03"; week = "53"}, + @{date="2010-01-04"; week = "01"} + ) { + param($date, $week) + Get-date -Date $date -uformat %V | Should -BeExactly $week } It "Passing '' to -uformat produces a descriptive error" -TestCases @(