diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index 2cdc6ee9731c4..9d02fee390685 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -1900,7 +1900,6 @@
-
diff --git a/src/libraries/System.Private.CoreLib/src/System/DateTime.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/DateTime.Unix.cs
index 0c35b864ff4c6..8dd87e3105d0b 100644
--- a/src/libraries/System.Private.CoreLib/src/System/DateTime.Unix.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/DateTime.Unix.cs
@@ -5,7 +5,7 @@ namespace System
{
public readonly partial struct DateTime
{
- internal const bool s_systemSupportsLeapSeconds = false;
+ internal static bool SystemSupportsLeapSeconds => false;
public static DateTime UtcNow
{
diff --git a/src/libraries/System.Private.CoreLib/src/System/DateTime.Win32.cs b/src/libraries/System.Private.CoreLib/src/System/DateTime.Win32.cs
deleted file mode 100644
index 15aca35c982ae..0000000000000
--- a/src/libraries/System.Private.CoreLib/src/System/DateTime.Win32.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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;
- }
- }
-}
diff --git a/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs
index 5ec5c7d0548a4..1b72fccb3f4ec 100644
--- a/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs
@@ -10,21 +10,21 @@ namespace System
{
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)
{
@@ -129,7 +129,16 @@ private static DateTime CreateDateTimeFromSystemTime(in Interop.Kernel32.SYSTEMT
return new DateTime(ticks);
}
- private static readonly unsafe delegate* unmanaged[SuppressGCTransition] 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] GetGetSystemTimeAsFileTimeFnPtr()
{
@@ -184,11 +193,11 @@ private static unsafe DateTime UpdateLeapSecondCacheAndReturnUtcNow()
// 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.
@@ -292,7 +301,7 @@ private static unsafe DateTime UpdateLeapSecondCacheAndReturnUtcNow()
// 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
@@ -318,11 +327,6 @@ static DateTime LowGranularityNonCachedFallback()
}
}
- // 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.
@@ -333,6 +337,16 @@ private sealed class LeapSecondCache
// 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] s_pfnGetSystemTimeAsFileTime = GetGetSystemTimeAsFileTimeFnPtr();
}
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/DateTime.cs b/src/libraries/System.Private.CoreLib/src/System/DateTime.cs
index bcf0d2dd8e0df..11c566195daf8 100644
--- a/src/libraries/System.Private.CoreLib/src/System/DateTime.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/DateTime.cs
@@ -273,7 +273,7 @@ public DateTime(int year, int month, int day, int hour, int minute, int second,
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);
@@ -291,7 +291,7 @@ public DateTime(int year, int month, int day, int hour, int minute, int second,
//
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);
}
@@ -307,7 +307,7 @@ public DateTime(int year, int month, int day, int hour, int minute, int 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);
@@ -327,7 +327,7 @@ public DateTime(int year, int month, int day, int hour, int minute, int second,
{
ArgumentNullException.ThrowIfNull(calendar);
- if (second != 60 || !s_systemSupportsLeapSeconds)
+ if (second != 60 || !SystemSupportsLeapSeconds)
{
_dateData = calendar.ToDateTime(year, month, day, hour, minute, second, 0).UTicks;
}
@@ -500,7 +500,7 @@ public DateTime(int year, int month, int day, int hour, int minute, int second,
{
ArgumentNullException.ThrowIfNull(calendar);
- if (second != 60 || !s_systemSupportsLeapSeconds)
+ if (second != 60 || !SystemSupportsLeapSeconds)
{
_dateData = calendar.ToDateTime(year, month, day, hour, minute, second, millisecond).UTicks;
}
@@ -777,7 +777,7 @@ private static ulong Init(int year, int month, int day, int hour, int minute, in
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;
@@ -1257,12 +1257,10 @@ public static DateTime FromFileTimeUtc(long fileTime)
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;
@@ -1696,12 +1694,10 @@ public long ToFileTimeUtc()
// 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)
@@ -1967,7 +1963,7 @@ internal static bool TryCreate(int year, int month, int day, int hour, int minut
{
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
diff --git a/src/libraries/System.Private.CoreLib/src/System/DateTimeOffset.cs b/src/libraries/System.Private.CoreLib/src/System/DateTimeOffset.cs
index b2289d1377ace..7c05f4ef5216b 100644
--- a/src/libraries/System.Private.CoreLib/src/System/DateTimeOffset.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/DateTimeOffset.cs
@@ -123,7 +123,7 @@ public DateTimeOffset(int year, int month, int day, int hour, int minute, int se
_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;
@@ -145,7 +145,7 @@ public DateTimeOffset(int year, int month, int day, int hour, int minute, int se
_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;
@@ -167,7 +167,7 @@ public DateTimeOffset(int year, int month, int day, int hour, int minute, int se
_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;