This enables AOT initialization of public readonly DateTime statics like DateTime.Min/MaxValue.
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeRegistryHandle.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\AppDomain.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffer.Windows.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\DateTime.Win32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\DateTime.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.Win32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.Windows.cs" />
{
public readonly partial struct DateTime
{
- internal const bool s_systemSupportsLeapSeconds = false;
+ internal static bool SystemSupportsLeapSeconds => false;
public static DateTime UtcNow
{
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-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,
- &slsi,
- (uint)sizeof(Interop.NtDll.SYSTEM_LEAP_SECOND_INFORMATION),
- null) == 0 && slsi.Enabled != Interop.BOOLEAN.FALSE;
- }
- }
-}
{
public readonly partial struct DateTime
{
- internal static readonly bool s_systemSupportsLeapSeconds = SystemSupportsLeapSeconds();
+ internal static bool SystemSupportsLeapSeconds => LeapSecondCache.s_systemSupportsLeapSeconds;
public static unsafe DateTime UtcNow
{
get
{
ulong fileTimeTmp; // mark only the temp local as address-taken
- s_pfnGetSystemTimeAsFileTime(&fileTimeTmp);
+ LeapSecondCache.s_pfnGetSystemTimeAsFileTime(&fileTimeTmp);
ulong fileTime = fileTimeTmp;
- if (s_systemSupportsLeapSeconds)
+ if (LeapSecondCache.s_systemSupportsLeapSeconds)
{
// Query the leap second cache first, which avoids expensive calls to GetFileTimeAsSystemTime.
- LeapSecondCache cacheValue = s_leapSecondCache;
+ LeapSecondCache cacheValue = LeapSecondCache.s_leapSecondCache;
ulong ticksSinceStartOfCacheValidityWindow = fileTime - cacheValue.OSFileTimeTicksAtStartOfValidityWindow;
if (ticksSinceStartOfCacheValidityWindow < LeapSecondCache.ValidityPeriodInTicks)
{
return new DateTime(ticks);
}
- private static readonly unsafe delegate* unmanaged[SuppressGCTransition]<ulong*, void> s_pfnGetSystemTimeAsFileTime = GetGetSystemTimeAsFileTimeFnPtr();
+ private static unsafe bool GetSystemSupportsLeapSeconds()
+ {
+ Interop.NtDll.SYSTEM_LEAP_SECOND_INFORMATION slsi;
+
+ return Interop.NtDll.NtQuerySystemInformation(
+ Interop.NtDll.SystemLeapSecondInformation,
+ &slsi,
+ (uint)sizeof(Interop.NtDll.SYSTEM_LEAP_SECOND_INFORMATION),
+ null) == 0 && slsi.Enabled != Interop.BOOLEAN.FALSE;
+ }
private static unsafe delegate* unmanaged[SuppressGCTransition]<ulong*, void> GetGetSystemTimeAsFileTimeFnPtr()
{
// OS update occurs and a past leap second is added, this limits the window in which our
// cache will return incorrect values.
- Debug.Assert(s_systemSupportsLeapSeconds);
+ Debug.Assert(SystemSupportsLeapSeconds);
Debug.Assert(LeapSecondCache.ValidityPeriodInTicks < TicksPerDay - TicksPerSecond, "Leap second cache validity window should be less than 23:59:59.");
ulong fileTimeNow;
- s_pfnGetSystemTimeAsFileTime(&fileTimeNow);
+ LeapSecondCache.s_pfnGetSystemTimeAsFileTime(&fileTimeNow);
// If we reached this point, our leap second cache is stale, and we need to update it.
// First, convert the FILETIME to a SYSTEMTIME.
// Finally, update the cache and return UtcNow.
Debug.Assert(fileTimeNow - fileTimeAtStartOfValidityWindow < LeapSecondCache.ValidityPeriodInTicks, "We should be within the validity window.");
- Volatile.Write(ref s_leapSecondCache, new LeapSecondCache()
+ Volatile.Write(ref LeapSecondCache.s_leapSecondCache, new LeapSecondCache()
{
OSFileTimeTicksAtStartOfValidityWindow = fileTimeAtStartOfValidityWindow,
DotnetDateDataAtStartOfValidityWindow = dotnetDateDataAtStartOfValidityWindow
}
}
- // The leap second cache. May be accessed by multiple threads simultaneously.
- // Writers must not mutate the object's fields after the reference is published.
- // Readers are not required to use volatile semantics.
- private static LeapSecondCache s_leapSecondCache = new LeapSecondCache();
-
private sealed class LeapSecondCache
{
// The length of the validity window. Must be less than 23:59:59.
// The DateTime._dateData value at the beginning of the validity window.
internal ulong DotnetDateDataAtStartOfValidityWindow;
+
+ // The leap second cache. May be accessed by multiple threads simultaneously.
+ // Writers must not mutate the object's fields after the reference is published.
+ // Readers are not required to use volatile semantics.
+ internal static LeapSecondCache s_leapSecondCache = new LeapSecondCache();
+
+ // The configuration of system leap seconds support is intentionally here to avoid blocking
+ // AOT pre-initialization of public readonly DateTime statics.
+ internal static readonly bool s_systemSupportsLeapSeconds = GetSystemSupportsLeapSeconds();
+ internal static readonly unsafe delegate* unmanaged[SuppressGCTransition]<ulong*, void> s_pfnGetSystemTimeAsFileTime = GetGetSystemTimeAsFileTimeFnPtr();
}
}
}
if ((uint)millisecond >= MillisPerSecond) ThrowMillisecondOutOfRange();
if ((uint)kind > (uint)DateTimeKind.Local) ThrowInvalidKind();
- if (second != 60 || !s_systemSupportsLeapSeconds)
+ if (second != 60 || !SystemSupportsLeapSeconds)
{
ulong ticks = calendar.ToDateTime(year, month, day, hour, minute, second, millisecond).UTicks;
_dateData = ticks | ((ulong)kind << KindShift);
//
public DateTime(int year, int month, int day, int hour, int minute, int second)
{
- if (second != 60 || !s_systemSupportsLeapSeconds)
+ if (second != 60 || !SystemSupportsLeapSeconds)
{
_dateData = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
}
{
if ((uint)kind > (uint)DateTimeKind.Local) ThrowInvalidKind();
- if (second != 60 || !s_systemSupportsLeapSeconds)
+ if (second != 60 || !SystemSupportsLeapSeconds)
{
ulong ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
_dateData = ticks | ((ulong)kind << KindShift);
{
ArgumentNullException.ThrowIfNull(calendar);
- if (second != 60 || !s_systemSupportsLeapSeconds)
+ if (second != 60 || !SystemSupportsLeapSeconds)
{
_dateData = calendar.ToDateTime(year, month, day, hour, minute, second, 0).UTicks;
}
{
ArgumentNullException.ThrowIfNull(calendar);
- if (second != 60 || !s_systemSupportsLeapSeconds)
+ if (second != 60 || !SystemSupportsLeapSeconds)
{
_dateData = calendar.ToDateTime(year, month, day, hour, minute, second, millisecond).UTicks;
}
if ((uint)millisecond >= MillisPerSecond) ThrowMillisecondOutOfRange();
if ((uint)kind > (uint)DateTimeKind.Local) ThrowInvalidKind();
- if (second != 60 || !s_systemSupportsLeapSeconds)
+ if (second != 60 || !SystemSupportsLeapSeconds)
{
ulong ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
ticks += (uint)millisecond * (uint)TicksPerMillisecond;
throw new ArgumentOutOfRangeException(nameof(fileTime), SR.ArgumentOutOfRange_FileTimeInvalid);
}
-#pragma warning disable 162 // Unrechable code on Unix
- if (s_systemSupportsLeapSeconds)
+ if (SystemSupportsLeapSeconds)
{
return FromFileTimeLeapSecondsAware((ulong)fileTime);
}
-#pragma warning restore 162
// This is the ticks in Universal time for this fileTime.
ulong universalTicks = (ulong)fileTime + FileTimeOffset;
// Treats the input as universal if it is not specified
long ticks = ((_dateData & KindLocal) != 0) ? ToUniversalTime().Ticks : Ticks;
-#pragma warning disable 162 // Unrechable code on Unix
- if (s_systemSupportsLeapSeconds)
+ if (SystemSupportsLeapSeconds)
{
return (long)ToFileTimeLeapSecondsAware(ticks);
}
-#pragma warning restore 162
ticks -= FileTimeOffset;
if (ticks < 0)
{
ticks += TimeToTicks(hour, minute, second) + (uint)millisecond * (uint)TicksPerMillisecond;
}
- else if (second == 60 && s_systemSupportsLeapSeconds && IsValidTimeWithLeapSeconds(year, month, day, hour, minute, DateTimeKind.Unspecified))
+ else if (second == 60 && SystemSupportsLeapSeconds && IsValidTimeWithLeapSeconds(year, month, day, hour, minute, DateTimeKind.Unspecified))
{
// if we have leap second (second = 60) then we'll need to check if it is valid time.
// if it is valid, then we adjust the second to 59 so DateTime will consider this second is last second
_offsetMinutes = ValidateOffset(offset);
int originalSecond = second;
- if (second == 60 && DateTime.s_systemSupportsLeapSeconds)
+ if (second == 60 && DateTime.SystemSupportsLeapSeconds)
{
// Reset the leap second to 59 for now and then we'll validate it after getting the final UTC time.
second = 59;
_offsetMinutes = ValidateOffset(offset);
int originalSecond = second;
- if (second == 60 && DateTime.s_systemSupportsLeapSeconds)
+ if (second == 60 && DateTime.SystemSupportsLeapSeconds)
{
// Reset the leap second to 59 for now and then we'll validate it after getting the final UTC time.
second = 59;
_offsetMinutes = ValidateOffset(offset);
int originalSecond = second;
- if (second == 60 && DateTime.s_systemSupportsLeapSeconds)
+ if (second == 60 && DateTime.SystemSupportsLeapSeconds)
{
// Reset the leap second to 59 for now and then we'll validate it after getting the final UTC time.
second = 59;