From f1dac25fc63638cdac52c51f2f3aea5c92ef3821 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Sun, 9 Dec 2018 13:21:32 -0800 Subject: [PATCH 1/4] Add DateTime Leap Seconds Tests --- .../tests/System/DateTimeTests.cs | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/src/System.Runtime/tests/System/DateTimeTests.cs b/src/System.Runtime/tests/System/DateTimeTests.cs index b2eefc53dc20..012a3510ebff 100644 --- a/src/System.Runtime/tests/System/DateTimeTests.cs +++ b/src/System.Runtime/tests/System/DateTimeTests.cs @@ -7,6 +7,7 @@ using System.Globalization; using System.Linq; using System.Runtime.Serialization; +using System.Runtime.InteropServices; using Xunit; namespace System.Tests @@ -721,7 +722,7 @@ public void Subtract_TimeSpan_ReturnsExpected(DateTime dateTime, TimeSpan timeSp Assert.Equal(expected, dateTime.Subtract(timeSpan)); Assert.Equal(expected, dateTime - timeSpan); } - + public static IEnumerable Subtract_OutOfRangeTimeSpan_TestData() { yield return new object[] { DateTime.Now, TimeSpan.MinValue }; @@ -2177,6 +2178,59 @@ public void GetObjectData_NullInfo_ThrowsArgumentNullException() AssertExtensions.Throws("info", () => ((ISerializable)DateTime.Now).GetObjectData(null, new StreamingContext())); } + [Fact] + public void TestRoundTrippingDateTimeAndFileTime() + { + // This test ensure the round tripping of DateTime with the system file time. + // It is important to have this working on systems support leap seconds as the conversion wouldn't be simple + // conversion but involve some OS calls to ensure the right conversion is happening. + + DateTime now = DateTime.UtcNow; + long fileTime = now.ToFileTimeUtc(); + DateTime roundTrippedDateTime = DateTime.FromFileTimeUtc(fileTime); + Assert.Equal(now, roundTrippedDateTime); + + now = DateTime.Now; + fileTime = now.ToFileTime(); + roundTrippedDateTime = DateTime.FromFileTime(fileTime); + Assert.Equal(now, roundTrippedDateTime); + } + + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public void TestTimeSynchronizationWithTheSystem() + { + // The reported time by the framework should be synchronized with the OS. + // There shouldn't be any shift by more than one second, otherwise there is something wrong. + // This test is useful when running on a system supporting leap seconds to ensure when the system + // has leap seconds, the framework reported time will still be synchronized. + + SYSTEMTIME st; + GetSystemTime(out st); + DateTime dt = DateTime.UtcNow; + + DateTime systemDateTimeNow = new DateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMillisecond, DateTimeKind.Utc); + TimeSpan diff = systemDateTimeNow - dt; + + Assert.True(diff < TimeSpan.FromSeconds(1), $"Reported DateTime.UtcNow {dt} is shifted by more than one second then the system time {systemDateTimeNow}"); + } + + [DllImport("Kernel32.dll")] + internal static extern void GetSystemTime(out SYSTEMTIME lpSystemTime); + + [StructLayout(LayoutKind.Sequential)] + internal struct SYSTEMTIME + { + internal ushort wYear; + internal ushort wMonth; + internal ushort wDayOfWeek; + internal ushort wDay; + internal ushort wHour; + internal ushort wMinute; + internal ushort wSecond; + internal ushort wMillisecond; + } + private class DateMaxCalendar : Calendar { public override int[] Eras => throw new NotImplementedException(); From 6f74d165d68cc1b3795e9319ec0948e7db786186 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Sun, 9 Dec 2018 19:45:16 -0800 Subject: [PATCH 2/4] Fix the comment --- src/System.Runtime/tests/System/DateTimeTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Runtime/tests/System/DateTimeTests.cs b/src/System.Runtime/tests/System/DateTimeTests.cs index 012a3510ebff..e9f513e8e493 100644 --- a/src/System.Runtime/tests/System/DateTimeTests.cs +++ b/src/System.Runtime/tests/System/DateTimeTests.cs @@ -2182,7 +2182,7 @@ public void GetObjectData_NullInfo_ThrowsArgumentNullException() public void TestRoundTrippingDateTimeAndFileTime() { // This test ensure the round tripping of DateTime with the system file time. - // It is important to have this working on systems support leap seconds as the conversion wouldn't be simple + // It is important to have this working on systems supporting leap seconds as the conversion wouldn't be simple // conversion but involve some OS calls to ensure the right conversion is happening. DateTime now = DateTime.UtcNow; From 6af9104b44fa73459a47a2d3d3c70f5ad864df9b Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Mon, 10 Dec 2018 12:06:40 -0800 Subject: [PATCH 3/4] Address the feedback --- .../tests/System/DateTimeTests.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/System.Runtime/tests/System/DateTimeTests.cs b/src/System.Runtime/tests/System/DateTimeTests.cs index e9f513e8e493..9a16024598da 100644 --- a/src/System.Runtime/tests/System/DateTimeTests.cs +++ b/src/System.Runtime/tests/System/DateTimeTests.cs @@ -2206,13 +2206,24 @@ public void TestTimeSynchronizationWithTheSystem() // has leap seconds, the framework reported time will still be synchronized. SYSTEMTIME st; + SYSTEMTIME st1; + GetSystemTime(out st); DateTime dt = DateTime.UtcNow; + GetSystemTime(out st1); + + DateTime systemDateTimeNow1 = new DateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMillisecond, DateTimeKind.Utc); + DateTime systemDateTimeNow2 = new DateTime(st1.wYear, st1.wMonth, st1.wDay, st1.wHour, st1.wMinute, st1.wSecond, st1.wMillisecond, DateTimeKind.Utc); - DateTime systemDateTimeNow = new DateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMillisecond, DateTimeKind.Utc); - TimeSpan diff = systemDateTimeNow - dt; + // Usually GetSystemTime and DateTime.UtcNow calls doesn't take one second to execute, if this is not the case then + // the thread was sleeping for awhile and we cannot test reliably on that case. - Assert.True(diff < TimeSpan.FromSeconds(1), $"Reported DateTime.UtcNow {dt} is shifted by more than one second then the system time {systemDateTimeNow}"); + TimeSpan diff = systemDateTimeNow2 - systemDateTimeNow1; + if (diff < TimeSpan.FromSeconds(1)) + { + diff = systemDateTimeNow1 - dt; + Assert.True(diff < TimeSpan.FromSeconds(1), $"Reported DateTime.UtcNow {dt} is shifted by more than one second then the system time {systemDateTimeNow1}"); + } } [DllImport("Kernel32.dll")] From ad2fadd479ae37f314ec33fb769f56fd8f3f5529 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Mon, 10 Dec 2018 18:12:56 -0800 Subject: [PATCH 4/4] small fix --- src/System.Runtime/tests/System/DateTimeTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Runtime/tests/System/DateTimeTests.cs b/src/System.Runtime/tests/System/DateTimeTests.cs index 9a16024598da..de967be4595e 100644 --- a/src/System.Runtime/tests/System/DateTimeTests.cs +++ b/src/System.Runtime/tests/System/DateTimeTests.cs @@ -2221,7 +2221,7 @@ public void TestTimeSynchronizationWithTheSystem() TimeSpan diff = systemDateTimeNow2 - systemDateTimeNow1; if (diff < TimeSpan.FromSeconds(1)) { - diff = systemDateTimeNow1 - dt; + diff = dt - systemDateTimeNow1; Assert.True(diff < TimeSpan.FromSeconds(1), $"Reported DateTime.UtcNow {dt} is shifted by more than one second then the system time {systemDateTimeNow1}"); } }