</ItemGroup>
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
<Compile Include="$(BclSourcesRoot)\Internal\Runtime\InteropServices\InMemoryAssemblyLoader.cs" />
- <Compile Include="$(BclSourcesRoot)\System\DateTime.Windows.cs" />
+ <Compile Include="$(BclSourcesRoot)\System\DateTime.Windows.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\Interop\Windows\OleAut32\Interop.VariantClear.cs" />
<Compile Include="$(BclSourcesRoot)\System\ApplicationModel.Windows.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\GlobalizationMode.Windows.cs" />
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class Kernel32
+ {
+ [DllImport(Libraries.Kernel32)]
+ internal static unsafe extern Interop.BOOL FileTimeToSystemTime(long* lpFileTime, Interop.Kernel32.SYSTEMTIME* lpSystemTime);
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class Kernel32
+ {
+ internal const int ProcessLeapSecondInfo = 8;
+
+ internal struct PROCESS_LEAP_SECOND_INFO
+ {
+ public uint Flags;
+ public uint Reserved;
+ }
+
+ [DllImport(Libraries.Kernel32)]
+ internal static unsafe extern Interop.BOOL GetProcessInformation(IntPtr hProcess, int ProcessInformationClass, void* ProcessInformation, int ProcessInformationSize);
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class Kernel32
+ {
+ [DllImport(Libraries.Kernel32)]
+ internal static unsafe extern void GetSystemTime(Interop.Kernel32.SYSTEMTIME* lpSystemTime);
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class Kernel32
+ {
+ [DllImport(Libraries.Kernel32)]
+ internal static unsafe extern void GetSystemTimeAsFileTime(long* lpSystemTimeAsFileTime);
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class Kernel32
+ {
+ [DllImport(Libraries.Kernel32)]
+ internal static unsafe extern void GetSystemTimePreciseAsFileTime(long* lpSystemTimeAsFileTime);
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class Kernel32
+ {
+ [DllImport(Libraries.Kernel32)]
+ internal static unsafe extern Interop.BOOL SystemTimeToFileTime(Interop.Kernel32.SYSTEMTIME* lpSystemTime, long* lpFileTime);
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class Kernel32
+ {
+ [DllImport(Libraries.Kernel32)]
+ internal static unsafe extern Interop.BOOL TzSpecificLocalTimeToSystemTime(
+ IntPtr lpTimeZoneInformation,
+ Interop.Kernel32.SYSTEMTIME* lpLocalTime,
+ Interop.Kernel32.SYSTEMTIME* lpUniversalTime);
+ }
+}
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.ExpandEnvironmentStrings.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FileAttributes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FILE_INFO_BY_HANDLE_CLASS.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FileTimeToSystemTime.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FileTypes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FindClose.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FindFirstFileEx.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetProcessTimes.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetSystemDirectoryW.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetSystemInfo.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetSystemTime.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetSystemTimeAsFileTime.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetSystemTimePreciseAsFileTime.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetSystemTimes.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetTempFileNameW.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetTempPathW.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetEndOfFile.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetThreadErrorMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetFilePointerEx.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SystemTimeToFileTime.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SYSTEM_INFO.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.TimeZone.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.TzSpecificLocalTimeToSystemTime.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.VirtualAlloc.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.VirtualFree.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.VirtualQuery.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Normaliz\Interop.Idna.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Normaliz\Interop.Normalization.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\NtDll\Interop.NtQuerySystemInformation.cs" Condition="'$(EnableWinRT)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Ole32\Interop.CoCreateGuid.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Secur32\Interop.GetUserNameExW.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Shell32\Interop.SHGetKnownFolderPath.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFileHandle.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFindHandle.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffer.Windows.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\DateTime.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\DebugProvider.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureInfo.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Windows.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Win32.cs" Condition="'$(EnableWinRT)' != 'true'" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.WinRT.cs" Condition="'$(EnableWinRT)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IdnMapping.Windows.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Win32.cs" Condition="'$(EnableWinRT)' != 'true'" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.WinRT.cs" Condition="'$(EnableWinRT)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Guid.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.TimeZone.Registry.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.VerifyVersionExW.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.VerSetConditionMask.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\NtDll\NtQueryInformationFile.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\NtDll\Interop.NtQuerySystemInformation.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\NtDll\Interop.NtQueryInformationFile.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\User32\Interop.Constants.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\User32\Interop.LoadString.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\User32\Interop.SendMessageTimeout.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\DateTime.Win32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.Win32.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Win32.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Win32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Win32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\TimeZoneInfo.Win32.cs" />
</ItemGroup>
<ItemGroup Condition="$(TargetsWindows) and '$(EnableWinRT)' == 'true'">
+ <Compile Include="$(MSBuildThisFileDirectory)System\DateTime.WinRT.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.WinRT.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.WinRT.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.WinRT.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.WinRT.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.CreateFile2.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.CREATEFILE2_EXTENDED_PARAMETERS.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetProcessInformation.cs" />
</ItemGroup>
<ItemGroup Condition="$(TargetsWindows) or '$(FeaturePal)'=='true'">
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeWaitHandle.Windows.cs" />
}
#endif
- internal static DateTime FromFileTimeLeapSecondsAware(long fileTime) => default;
- internal static long ToFileTimeLeapSecondsAware(long ticks) => default;
+ private static DateTime FromFileTimeLeapSecondsAware(long fileTime) => default;
+ private static long ToFileTimeLeapSecondsAware(long ticks) => default;
// IsValidTimeWithLeapSeconds is not expected to be called at all for now on non-Windows platforms
internal static bool IsValidTimeWithLeapSeconds(int year, int month, int day, int hour, int minute, int second, DateTimeKind kind) => false;
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace System
+{
+ public readonly partial struct DateTime
+ {
+ private static unsafe bool SystemSupportsLeapSeconds()
+ {
+ Interop.NtDll.SYSTEM_LEAP_SECOND_INFORMATION slsi;
+
+ return Interop.NtDll.NtQuerySystemInformation(
+ Interop.NtDll.SystemLeapSecondInformation,
+ (void *) &slsi,
+ sizeof(Interop.NtDll.SYSTEM_LEAP_SECOND_INFORMATION),
+ null) == 0 && slsi.Enabled;
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace System
+{
+ public readonly partial struct DateTime
+ {
+ private static unsafe bool SystemSupportsLeapSeconds()
+ {
+ Interop.Kernel32.PROCESS_LEAP_SECOND_INFO info;
+
+ // Store apps don't have access to an API that would let us find out whether leap seconds have been
+ // disabled by policy: this implementation will produce slightly different results from what
+ // we have for Win32. If GetProcessInformation succeeds, we have to act as if leap seconds existed.
+ // They could still have been disabled by policy, but we have no way to check for that.
+ return Interop.Kernel32.GetProcessInformation(
+ Interop.Kernel32.GetCurrentProcess(),
+ Interop.Kernel32.ProcessLeapSecondInfo,
+ &info,
+ sizeof(Interop.Kernel32.PROCESS_LEAP_SECOND_INFO)) != Interop.BOOL.FALSE;
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace System
+{
+ public readonly partial struct DateTime
+ {
+ internal static readonly bool s_systemSupportsLeapSeconds = SystemSupportsLeapSeconds();
+
+ public static unsafe DateTime UtcNow
+ {
+ get
+ {
+ if (s_systemSupportsLeapSeconds)
+ {
+ FullSystemTime time;
+ GetSystemTimeWithLeapSecondsHandling(&time);
+ return CreateDateTimeFromSystemTime(in time);
+ }
+
+ return new DateTime(((ulong)(GetSystemTimeAsFileTime() + FileTimeOffset)) | KindUtc);
+ }
+ }
+
+ internal static unsafe bool IsValidTimeWithLeapSeconds(int year, int month, int day, int hour, int minute, int second, DateTimeKind kind)
+ {
+ DateTime dt = new DateTime(year, month, day);
+ FullSystemTime time = new FullSystemTime(year, month, dt.DayOfWeek, day, hour, minute, second);
+
+ switch (kind)
+ {
+ case DateTimeKind.Local: return ValidateSystemTime(&time.systemTime, localTime: true);
+ case DateTimeKind.Utc: return ValidateSystemTime(&time.systemTime, localTime: false);
+ default:
+ return ValidateSystemTime(&time.systemTime, localTime: true) || ValidateSystemTime(&time.systemTime, localTime: false);
+ }
+ }
+
+ private static unsafe DateTime FromFileTimeLeapSecondsAware(long fileTime)
+ {
+ FullSystemTime time;
+ if (FileTimeToSystemTime(fileTime, &time))
+ {
+ return CreateDateTimeFromSystemTime(in time);
+ }
+
+ throw new ArgumentOutOfRangeException(nameof(fileTime), SR.ArgumentOutOfRange_DateTimeBadTicks);
+ }
+
+ private static unsafe long ToFileTimeLeapSecondsAware(long ticks)
+ {
+ FullSystemTime time = new FullSystemTime(ticks);
+ long fileTime;
+
+ if (SystemTimeToFileTime(&time.systemTime, &fileTime))
+ {
+ return fileTime + ticks % TicksPerMillisecond;
+ }
+
+ throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_FileTimeInvalid);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static DateTime CreateDateTimeFromSystemTime(in FullSystemTime time)
+ {
+ long ticks = DateToTicks(time.systemTime.Year, time.systemTime.Month, time.systemTime.Day);
+ ticks += TimeToTicks(time.systemTime.Hour, time.systemTime.Minute, time.systemTime.Second);
+ ticks += time.systemTime.Milliseconds * TicksPerMillisecond;
+ ticks += time.hundredNanoSecond;
+ return new DateTime( ((UInt64)(ticks)) | KindUtc);
+ }
+
+ // FullSystemTime struct is the SYSTEMTIME struct with extra hundredNanoSecond field to store more precise time.
+ [StructLayout(LayoutKind.Sequential)]
+ private struct FullSystemTime
+ {
+ internal Interop.Kernel32.SYSTEMTIME systemTime;
+ internal long hundredNanoSecond;
+
+ internal FullSystemTime(int year, int month, DayOfWeek dayOfWeek, int day, int hour, int minute, int second)
+ {
+ systemTime.Year = (ushort) year;
+ systemTime.Month = (ushort) month;
+ systemTime.DayOfWeek = (ushort) dayOfWeek;
+ systemTime.Day = (ushort) day;
+ systemTime.Hour = (ushort) hour;
+ systemTime.Minute = (ushort) minute;
+ systemTime.Second = (ushort) second;
+ systemTime.Milliseconds = 0;
+ hundredNanoSecond = 0;
+ }
+
+ internal FullSystemTime(long ticks)
+ {
+ DateTime dt = new DateTime(ticks);
+
+ int year, month, day;
+ dt.GetDatePart(out year, out month, out day);
+
+ systemTime.Year = (ushort) year;
+ systemTime.Month = (ushort) month;
+ systemTime.DayOfWeek = (ushort) dt.DayOfWeek;
+ systemTime.Day = (ushort) day;
+ systemTime.Hour = (ushort) dt.Hour;
+ systemTime.Minute = (ushort) dt.Minute;
+ systemTime.Second = (ushort) dt.Second;
+ systemTime.Milliseconds = (ushort) dt.Millisecond;
+ hundredNanoSecond = 0;
+ }
+ };
+
+#if !CORECLR
+ internal static readonly bool s_systemSupportsPreciseSystemTime = SystemSupportsPreciseSystemTime();
+
+ private static unsafe bool SystemSupportsPreciseSystemTime()
+ {
+ if (Environment.IsWindows8OrAbove)
+ {
+ // GetSystemTimePreciseAsFileTime exists and we'd like to use it. However, on
+ // misconfigured systems, it's possible for the "precise" time to be inaccurate:
+ // https://github.com/dotnet/coreclr/issues/14187
+ // If it's inaccurate, though, we expect it to be wildly inaccurate, so as a
+ // workaround/heuristic, we get both the "normal" and "precise" times, and as
+ // long as they're close, we use the precise one. This workaround can be removed
+ // when we better understand what's causing the drift and the issue is no longer
+ // a problem or can be better worked around on all targeted OSes.
+
+ long systemTimeResult;
+ Interop.Kernel32.GetSystemTimeAsFileTime(&systemTimeResult);
+
+ long preciseSystemTimeResult;
+ Interop.Kernel32.GetSystemTimePreciseAsFileTime(&preciseSystemTimeResult);
+
+ return Math.Abs(preciseSystemTimeResult - systemTimeResult) <= 100 * TicksPerMillisecond;
+ }
+
+ return false;
+ }
+
+ private static unsafe bool ValidateSystemTime(Interop.Kernel32.SYSTEMTIME* time, bool localTime)
+ {
+ if (localTime)
+ {
+ Interop.Kernel32.SYSTEMTIME st;
+ return Interop.Kernel32.TzSpecificLocalTimeToSystemTime(IntPtr.Zero, time, &st) != Interop.BOOL.FALSE;
+ }
+ else
+ {
+ long timestamp;
+ return Interop.Kernel32.SystemTimeToFileTime(time, ×tamp) != Interop.BOOL.FALSE;
+ }
+ }
+
+ private static unsafe bool FileTimeToSystemTime(long fileTime, FullSystemTime* time)
+ {
+ if (Interop.Kernel32.FileTimeToSystemTime(&fileTime, &time->systemTime) != Interop.BOOL.FALSE)
+ {
+ // to keep the time precision
+ time->hundredNanoSecond = fileTime % TicksPerMillisecond;
+ if (time->systemTime.Second > 59)
+ {
+ // we have a leap second, force it to last second in the minute as DateTime doesn't account for leap seconds in its calculation.
+ // we use the maxvalue from the milliseconds and the 100-nano seconds to avoid reporting two out of order 59 seconds
+ time->systemTime.Second = 59;
+ time->systemTime.Milliseconds = 999;
+ time->hundredNanoSecond = 9999;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private static unsafe void GetSystemTimeWithLeapSecondsHandling(FullSystemTime* time)
+ {
+ if (!FileTimeToSystemTime(GetSystemTimeAsFileTime(), time))
+ {
+ Interop.Kernel32.GetSystemTime(&time->systemTime);
+ time->hundredNanoSecond = 0;
+ if (time->systemTime.Second > 59)
+ {
+ // we have a leap second, force it to last second in the minute as DateTime doesn't account for leap seconds in its calculation.
+ // we use the maxvalue from the milliseconds and the 100-nano seconds to avoid reporting two out of order 59 seconds
+ time->systemTime.Second = 59;
+ time->systemTime.Milliseconds = 999;
+ time->hundredNanoSecond = 9999;
+ }
+ }
+ }
+
+ private static unsafe bool SystemTimeToFileTime(Interop.Kernel32.SYSTEMTIME* time, long* fileTime)
+ {
+ return Interop.Kernel32.SystemTimeToFileTime(time, fileTime) != Interop.BOOL.FALSE;
+ }
+
+ private static unsafe long GetSystemTimeAsFileTime()
+ {
+ long timestamp;
+
+ if (s_systemSupportsPreciseSystemTime)
+ {
+ Interop.Kernel32.GetSystemTimePreciseAsFileTime(×tamp);
+ }
+ else
+ {
+ Interop.Kernel32.GetSystemTimeAsFileTime(×tamp);
+ }
+
+ return timestamp;
+ }
+#endif
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace System
+{
+ public readonly partial struct DateTime
+ {
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static unsafe extern bool ValidateSystemTime(Interop.Kernel32.SYSTEMTIME* time, bool localTime);
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static unsafe extern bool FileTimeToSystemTime(long fileTime, FullSystemTime* time);
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static unsafe extern void GetSystemTimeWithLeapSecondsHandling(FullSystemTime* time);
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static unsafe extern bool SystemTimeToFileTime(Interop.Kernel32.SYSTEMTIME* time, long* fileTime);
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static unsafe extern long GetSystemTimeAsFileTime();
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace System
-{
- public readonly partial struct DateTime
- {
- internal static readonly bool s_systemSupportsLeapSeconds = SystemSupportsLeapSeconds();
-
- public static DateTime UtcNow
- {
- get
- {
- if (s_systemSupportsLeapSeconds)
- {
- GetSystemTimeWithLeapSecondsHandling(out FullSystemTime time);
- return CreateDateTimeFromSystemTime(in time);
- }
-
- return new DateTime(((ulong)(GetSystemTimeAsFileTime() + FileTimeOffset)) | KindUtc);
- }
- }
-
- internal static bool IsValidTimeWithLeapSeconds(int year, int month, int day, int hour, int minute, int second, DateTimeKind kind)
- {
- DateTime dt = new DateTime(year, month, day);
- FullSystemTime time = new FullSystemTime(year, month, dt.DayOfWeek, day, hour, minute, second);
-
- switch (kind)
- {
- case DateTimeKind.Local: return ValidateSystemTime(in time.systemTime, localTime: true);
- case DateTimeKind.Utc: return ValidateSystemTime(in time.systemTime, localTime: false);
- default:
- return ValidateSystemTime(in time.systemTime, localTime: true) || ValidateSystemTime(in time.systemTime, localTime: false);
- }
- }
-
- internal static DateTime FromFileTimeLeapSecondsAware(long fileTime)
- {
- if (FileTimeToSystemTime(fileTime, out FullSystemTime time))
- {
- return CreateDateTimeFromSystemTime(in time);
- }
-
- throw new ArgumentOutOfRangeException("fileTime", SR.ArgumentOutOfRange_DateTimeBadTicks);
- }
-
- internal static long ToFileTimeLeapSecondsAware(long ticks)
- {
- FullSystemTime time = new FullSystemTime(ticks);
- if (SystemTimeToFileTime(in time.systemTime, out long fileTime))
- {
- return fileTime + ticks % TicksPerMillisecond;
- }
-
- throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_FileTimeInvalid);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static DateTime CreateDateTimeFromSystemTime(in FullSystemTime time)
- {
- long ticks = DateToTicks(time.systemTime.Year, time.systemTime.Month, time.systemTime.Day);
- ticks += TimeToTicks(time.systemTime.Hour, time.systemTime.Minute, time.systemTime.Second);
- ticks += time.systemTime.Milliseconds * TicksPerMillisecond;
- ticks += time.hundredNanoSecond;
- return new DateTime( ((UInt64)(ticks)) | KindUtc);
- }
-
- private static unsafe bool SystemSupportsLeapSeconds()
- {
- Interop.NtDll.SYSTEM_LEAP_SECOND_INFORMATION slsi;
-
- return Interop.NtDll.NtQuerySystemInformation(
- Interop.NtDll.SystemLeapSecondInformation,
- (void *) &slsi,
- sizeof(Interop.NtDll.SYSTEM_LEAP_SECOND_INFORMATION),
- null) == 0 && slsi.Enabled;
- }
-
- // FullSystemTime struct is the SYSTEMTIME struct with extra hundredNanoSecond field to store more precise time.
- [StructLayout(LayoutKind.Sequential)]
- internal struct FullSystemTime
- {
- internal Interop.Kernel32.SYSTEMTIME systemTime;
- internal long hundredNanoSecond;
-
- internal FullSystemTime(int year, int month, DayOfWeek dayOfWeek, int day, int hour, int minute, int second)
- {
- systemTime.Year = (ushort) year;
- systemTime.Month = (ushort) month;
- systemTime.DayOfWeek = (ushort) dayOfWeek;
- systemTime.Day = (ushort) day;
- systemTime.Hour = (ushort) hour;
- systemTime.Minute = (ushort) minute;
- systemTime.Second = (ushort) second;
- systemTime.Milliseconds = 0;
- hundredNanoSecond = 0;
- }
-
- internal FullSystemTime(long ticks)
- {
- DateTime dt = new DateTime(ticks);
-
- int year, month, day;
- dt.GetDatePart(out year, out month, out day);
-
- systemTime.Year = (ushort) year;
- systemTime.Month = (ushort) month;
- systemTime.DayOfWeek = (ushort) dt.DayOfWeek;
- systemTime.Day = (ushort) day;
- systemTime.Hour = (ushort) dt.Hour;
- systemTime.Minute = (ushort) dt.Minute;
- systemTime.Second = (ushort) dt.Second;
- systemTime.Milliseconds = (ushort) dt.Millisecond;
- hundredNanoSecond = 0;
- }
- };
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern bool ValidateSystemTime(in Interop.Kernel32.SYSTEMTIME time, bool localTime);
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern bool FileTimeToSystemTime(long fileTime, out FullSystemTime time);
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern void GetSystemTimeWithLeapSecondsHandling(out FullSystemTime time);
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern bool SystemTimeToFileTime(in Interop.Kernel32.SYSTEMTIME time, out long fileTime);
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern long GetSystemTimeAsFileTime();
- }
-}