diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index a2a5b776f4cbd..36b60ed6663a3 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -285,12 +285,10 @@
-
-
Common\Interop\Windows\OleAut32\Interop.VariantClear.cs
diff --git a/src/coreclr/System.Private.CoreLib/src/System/DateTime.Unix.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/DateTime.Unix.CoreCLR.cs
deleted file mode 100644
index 3dc69ae32b1d0..0000000000000
--- a/src/coreclr/System.Private.CoreLib/src/System/DateTime.Unix.CoreCLR.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Runtime.CompilerServices;
-
-namespace System
-{
- public readonly partial struct DateTime
- {
- public static DateTime UtcNow
- {
- get
- {
- return new DateTime(((ulong)(GetSystemTimeAsFileTime() + FileTimeOffset)) | KindUtc);
- }
- }
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern long GetSystemTimeAsFileTime();
- }
-}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/DateTime.Windows.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/DateTime.Windows.CoreCLR.cs
deleted file mode 100644
index 1f77180f47870..0000000000000
--- a/src/coreclr/System.Private.CoreLib/src/System/DateTime.Windows.CoreCLR.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Runtime.CompilerServices;
-
-namespace System
-{
- public readonly partial struct DateTime
- {
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern unsafe bool ValidateSystemTime(Interop.Kernel32.SYSTEMTIME* time, bool localTime);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern unsafe bool FileTimeToSystemTime(long fileTime, FullSystemTime* time);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern unsafe void GetSystemTimeWithLeapSecondsHandling(FullSystemTime* time);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern unsafe bool SystemTimeToFileTime(Interop.Kernel32.SYSTEMTIME* time, long* fileTime);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern unsafe long GetSystemTimeAsFileTime();
- }
-}
diff --git a/src/coreclr/classlibnative/bcltype/system.cpp b/src/coreclr/classlibnative/bcltype/system.cpp
index 3660c14963df9..91a39ef9d0892 100644
--- a/src/coreclr/classlibnative/bcltype/system.cpp
+++ b/src/coreclr/classlibnative/bcltype/system.cpp
@@ -30,157 +30,7 @@
#include "array.h"
#include "eepolicy.h"
-#ifndef TARGET_UNIX
-typedef void(WINAPI *pfnGetSystemTimeAsFileTime)(LPFILETIME lpSystemTimeAsFileTime);
-extern pfnGetSystemTimeAsFileTime g_pfnGetSystemTimeAsFileTime;
-
-void WINAPI InitializeGetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime)
-{
- pfnGetSystemTimeAsFileTime func = NULL;
-
- HMODULE hKernel32 = WszLoadLibrary(W("kernel32.dll"));
- if (hKernel32 != NULL)
- {
- func = (pfnGetSystemTimeAsFileTime)GetProcAddress(hKernel32, "GetSystemTimePreciseAsFileTime");
- if (func != NULL)
- {
- // 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/runtime/issues/9014
- // 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.
-
- FILETIME systemTimeResult;
- ::GetSystemTimeAsFileTime(&systemTimeResult);
-
- FILETIME preciseSystemTimeResult;
- func(&preciseSystemTimeResult);
-
- LONG64 systemTimeLong100ns = (LONG64)((((ULONG64)systemTimeResult.dwHighDateTime) << 32) | (ULONG64)systemTimeResult.dwLowDateTime);
- LONG64 preciseSystemTimeLong100ns = (LONG64)((((ULONG64)preciseSystemTimeResult.dwHighDateTime) << 32) | (ULONG64)preciseSystemTimeResult.dwLowDateTime);
-
- const INT32 THRESHOLD_100NS = 1000000; // 100ms
- if (abs(preciseSystemTimeLong100ns - systemTimeLong100ns) > THRESHOLD_100NS)
- {
- // Too much difference. Don't use GetSystemTimePreciseAsFileTime.
- func = NULL;
- }
- }
- }
- if (func == NULL)
- {
- func = &::GetSystemTimeAsFileTime;
- }
-
- InterlockedCompareExchangeT(&g_pfnGetSystemTimeAsFileTime, func, &InitializeGetSystemTimeAsFileTime);
-
- g_pfnGetSystemTimeAsFileTime(lpSystemTimeAsFileTime);
-}
-
-pfnGetSystemTimeAsFileTime g_pfnGetSystemTimeAsFileTime = &InitializeGetSystemTimeAsFileTime;
-#endif // TARGET_UNIX
-
-FCIMPL0(INT64, SystemNative::__GetSystemTimeAsFileTime)
-{
- FCALL_CONTRACT;
-
- INT64 timestamp;
-#ifndef TARGET_UNIX
- g_pfnGetSystemTimeAsFileTime((FILETIME*)×tamp);
-#else
- GetSystemTimeAsFileTime((FILETIME*)×tamp);
-#endif
-
-#if BIGENDIAN
- timestamp = (INT64)(((UINT64)timestamp >> 32) | ((UINT64)timestamp << 32));
-#endif
-
- return timestamp;
-}
-FCIMPLEND;
-
-
-#ifndef TARGET_UNIX
-
-FCIMPL1(VOID, SystemNative::GetSystemTimeWithLeapSecondsHandling, FullSystemTime *time)
-{
- FCALL_CONTRACT;
- INT64 timestamp;
-
- g_pfnGetSystemTimeAsFileTime((FILETIME*)×tamp);
-
- if (::FileTimeToSystemTime((FILETIME*)×tamp, &(time->systemTime)))
- {
- // to keep the time precision
- time->hundredNanoSecond = timestamp % 10000; // 10000 is the number of 100-nano seconds per Millisecond
- }
- else
- {
- ::GetSystemTime(&(time->systemTime));
- time->hundredNanoSecond = 0;
- }
-
- if (time->systemTime.wSecond > 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.wSecond = 59;
- time->systemTime.wMilliseconds = 999;
- time->hundredNanoSecond = 9999;
- }
-}
-FCIMPLEND;
-FCIMPL2(FC_BOOL_RET, SystemNative::FileTimeToSystemTime, INT64 fileTime, FullSystemTime *time)
-{
- FCALL_CONTRACT;
- if (::FileTimeToSystemTime((FILETIME*)&fileTime, (LPSYSTEMTIME) time))
- {
- // to keep the time precision
- time->hundredNanoSecond = fileTime % 10000; // 10000 is the number of 100-nano seconds per Millisecond
- if (time->systemTime.wSecond > 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.wSecond = 59;
- time->systemTime.wMilliseconds = 999;
- time->hundredNanoSecond = 9999;
- }
- FC_RETURN_BOOL(TRUE);
- }
- FC_RETURN_BOOL(FALSE);
-}
-FCIMPLEND;
-
-FCIMPL2(FC_BOOL_RET, SystemNative::ValidateSystemTime, SYSTEMTIME *time, CLR_BOOL localTime)
-{
- FCALL_CONTRACT;
-
- if (localTime)
- {
- SYSTEMTIME st;
- FC_RETURN_BOOL(::TzSpecificLocalTimeToSystemTime(NULL, time, &st));
- }
- else
- {
- FILETIME timestamp;
- FC_RETURN_BOOL(::SystemTimeToFileTime(time, ×tamp));
- }
-}
-FCIMPLEND;
-
-FCIMPL2(FC_BOOL_RET, SystemNative::SystemTimeToFileTime, SYSTEMTIME *time, INT64 *pFileTime)
-{
- FCALL_CONTRACT;
-
- BOOL ret = ::SystemTimeToFileTime(time, (LPFILETIME) pFileTime);
- FC_RETURN_BOOL(ret);
-}
-FCIMPLEND;
-#endif // TARGET_UNIX
FCIMPL0(UINT32, SystemNative::GetTickCount)
diff --git a/src/coreclr/classlibnative/bcltype/system.h b/src/coreclr/classlibnative/bcltype/system.h
index 5bbf73d4a1048..fe8b1e476a160 100644
--- a/src/coreclr/classlibnative/bcltype/system.h
+++ b/src/coreclr/classlibnative/bcltype/system.h
@@ -43,13 +43,6 @@ class SystemNative
public:
// Functions on the System.Environment class
-#ifndef TARGET_UNIX
- static FCDECL1(VOID, GetSystemTimeWithLeapSecondsHandling, FullSystemTime *time);
- static FCDECL2(FC_BOOL_RET, ValidateSystemTime, SYSTEMTIME *time, CLR_BOOL localTime);
- static FCDECL2(FC_BOOL_RET, FileTimeToSystemTime, INT64 fileTime, FullSystemTime *time);
- static FCDECL2(FC_BOOL_RET, SystemTimeToFileTime, SYSTEMTIME *time, INT64 *pFileTime);
-#endif // TARGET_UNIX
- static FCDECL0(INT64, __GetSystemTimeAsFileTime);
static FCDECL0(UINT32, GetTickCount);
static FCDECL0(UINT64, GetTickCount64);
diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h
index bdab73a937776..e34f84c6125c8 100644
--- a/src/coreclr/vm/ecalllist.h
+++ b/src/coreclr/vm/ecalllist.h
@@ -131,16 +131,6 @@ FCFuncStart(gDiagnosticsStackTrace)
FCFuncElement("GetStackFramesInternal", DebugStackTrace::GetStackFramesInternal)
FCFuncEnd()
-FCFuncStart(gDateTimeFuncs)
-#if !defined(TARGET_UNIX)
- FCFuncElement("GetSystemTimeWithLeapSecondsHandling", SystemNative::GetSystemTimeWithLeapSecondsHandling)
- FCFuncElement("ValidateSystemTime", SystemNative::ValidateSystemTime)
- FCFuncElement("FileTimeToSystemTime", SystemNative::FileTimeToSystemTime)
- FCFuncElement("SystemTimeToFileTime", SystemNative::SystemTimeToFileTime)
-#endif // TARGET_UNIX
- FCFuncElement("GetSystemTimeAsFileTime", SystemNative::__GetSystemTimeAsFileTime)
-FCFuncEnd()
-
FCFuncStart(gEnvironmentFuncs)
FCFuncElement("get_CurrentManagedThreadId", JIT_GetCurrentManagedThreadId)
FCFuncElement("get_TickCount", SystemNative::GetTickCount)
@@ -1121,7 +1111,6 @@ FCClassElement("ComWrappers", "System.Runtime.InteropServices", gComWrappersFunc
FCClassElement("CompatibilitySwitch", "System.Runtime.Versioning", gCompatibilitySwitchFuncs)
FCClassElement("CustomAttribute", "System.Reflection", gCOMCustomAttributeFuncs)
FCClassElement("CustomAttributeEncodedArgument", "System.Reflection", gCustomAttributeEncodedArgument)
-FCClassElement("DateTime", "System", gDateTimeFuncs)
FCClassElement("Debugger", "System.Diagnostics", gDiagnosticsDebugger)
FCClassElement("Delegate", "System", gDelegateFuncs)
FCClassElement("DependentHandle", "System.Runtime.CompilerServices", gDependentHandleFuncs)
diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetSystemTimeAsTicks.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetSystemTimeAsTicks.cs
index 6811f5b45bfc4..359d3775f02b1 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetSystemTimeAsTicks.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetSystemTimeAsTicks.cs
@@ -8,6 +8,7 @@ internal static partial class Interop
internal partial class Sys
{
[DllImport(Interop.Libraries.SystemNative, EntryPoint = "SystemNative_GetSystemTimeAsTicks")]
+ [SuppressGCTransition]
internal static extern long GetSystemTimeAsTicks();
}
}
diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FileTimeToSystemTime.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FileTimeToSystemTime.cs
index 95b98e47d3b0c..3a219035f6197 100644
--- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FileTimeToSystemTime.cs
+++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FileTimeToSystemTime.cs
@@ -8,6 +8,7 @@ internal static partial class Interop
internal static partial class Kernel32
{
[DllImport(Libraries.Kernel32)]
+ [SuppressGCTransition]
internal static extern unsafe Interop.BOOL FileTimeToSystemTime(long* lpFileTime, Interop.Kernel32.SYSTEMTIME* lpSystemTime);
}
}
diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetSystemTime.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetSystemTime.cs
index 78ab4e93c2fa2..8f49121906c02 100644
--- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetSystemTime.cs
+++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetSystemTime.cs
@@ -8,6 +8,7 @@ internal static partial class Interop
internal static partial class Kernel32
{
[DllImport(Libraries.Kernel32)]
+ [SuppressGCTransition]
internal static extern unsafe void GetSystemTime(Interop.Kernel32.SYSTEMTIME* lpSystemTime);
}
}
diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetSystemTimeAsFileTime.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetSystemTimeAsFileTime.cs
deleted file mode 100644
index cae4594d9a353..0000000000000
--- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetSystemTimeAsFileTime.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Runtime.InteropServices;
-
-internal static partial class Interop
-{
- internal static partial class Kernel32
- {
- [DllImport(Libraries.Kernel32)]
- internal static extern unsafe void GetSystemTimeAsFileTime(long* lpSystemTimeAsFileTime);
- }
-}
diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetSystemTimePreciseAsFileTime.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetSystemTimePreciseAsFileTime.cs
deleted file mode 100644
index 0f79e01529024..0000000000000
--- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetSystemTimePreciseAsFileTime.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Runtime.InteropServices;
-
-internal static partial class Interop
-{
- internal static partial class Kernel32
- {
- [DllImport(Libraries.Kernel32)]
- internal static extern unsafe void GetSystemTimePreciseAsFileTime(long* lpSystemTimeAsFileTime);
- }
-}
diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SystemTimeToFileTime.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SystemTimeToFileTime.cs
index 852053b6c5f31..69a4a4622d336 100644
--- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SystemTimeToFileTime.cs
+++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SystemTimeToFileTime.cs
@@ -8,6 +8,7 @@ internal static partial class Interop
internal static partial class Kernel32
{
[DllImport(Libraries.Kernel32)]
+ [SuppressGCTransition]
internal static extern unsafe Interop.BOOL SystemTimeToFileTime(Interop.Kernel32.SYSTEMTIME* lpSystemTime, long* lpFileTime);
}
}
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 dafa471e67f9c..af8dac2c31374 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
@@ -1401,12 +1401,6 @@
Common\Interop\Windows\Kernel32\Interop.GetSystemTime.cs
-
- Common\Interop\Windows\Kernel32\Interop.GetSystemTimeAsFileTime.cs
-
-
- Common\Interop\Windows\Kernel32\Interop.GetSystemTimePreciseAsFileTime.cs
-
Common\Interop\Windows\Kernel32\Interop.GetSystemTimes.cs
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 000c72db38c3b..7c1df12cbdf76 100644
--- a/src/libraries/System.Private.CoreLib/src/System/DateTime.Unix.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/DateTime.Unix.cs
@@ -7,7 +7,6 @@ public readonly partial struct DateTime
{
internal const bool s_systemSupportsLeapSeconds = false;
-#if !CORECLR
public static DateTime UtcNow
{
get
@@ -15,7 +14,6 @@ public static DateTime UtcNow
return new DateTime(((ulong)(Interop.Sys.GetSystemTimeAsTicks() + UnixEpochTicks)) | KindUtc);
}
}
-#endif
private static DateTime FromFileTimeLeapSecondsAware(long fileTime) => default;
private static long ToFileTimeLeapSecondsAware(long ticks) => default;
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 ac4e1fe6be116..a348414c4065a 100644
--- a/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs
@@ -14,14 +14,39 @@ public static unsafe DateTime UtcNow
{
get
{
+ long fileTime;
+ s_pfnGetSystemTimeAsFileTime(&fileTime);
+
if (s_systemSupportsLeapSeconds)
{
FullSystemTime time;
- GetSystemTimeWithLeapSecondsHandling(&time);
+
+ if (Interop.Kernel32.FileTimeToSystemTime(&fileTime, &time.systemTime) != Interop.BOOL.FALSE)
+ {
+ // to keep the time precision
+ time.hundredNanoSecond = fileTime % 10000; // 10000 is the number of 100-nano seconds per Millisecond
+ }
+ else
+ {
+ 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;
+ }
+
return CreateDateTimeFromSystemTime(in time);
}
-
- return new DateTime(((ulong)(GetSystemTimeAsFileTime() + FileTimeOffset)) | KindUtc);
+ else
+ {
+ return new DateTime(((ulong)(fileTime + FileTimeOffset)) | KindUtc);
+ }
}
}
@@ -30,23 +55,42 @@ internal static unsafe bool IsValidTimeWithLeapSeconds(int year, int month, int
DateTime dt = new DateTime(year, month, day);
FullSystemTime time = new FullSystemTime(year, month, dt.DayOfWeek, day, hour, minute, second);
- return kind switch
+ if (kind != DateTimeKind.Utc)
{
- DateTimeKind.Local => ValidateSystemTime(&time.systemTime, localTime: true),
- DateTimeKind.Utc => ValidateSystemTime(&time.systemTime, localTime: false),
- _ => ValidateSystemTime(&time.systemTime, localTime: true) || ValidateSystemTime(&time.systemTime, localTime: false),
- };
+ Interop.Kernel32.SYSTEMTIME st;
+ if (Interop.Kernel32.TzSpecificLocalTimeToSystemTime(IntPtr.Zero, &time.systemTime, &st) != Interop.BOOL.FALSE)
+ return true;
+ }
+
+ if (kind != DateTimeKind.Local)
+ {
+ long ft;
+ if (Interop.Kernel32.SystemTimeToFileTime(&time.systemTime, &ft) != Interop.BOOL.FALSE)
+ return true;
+ }
+
+ return false;
}
private static unsafe DateTime FromFileTimeLeapSecondsAware(long fileTime)
{
FullSystemTime time;
- if (FileTimeToSystemTime(fileTime, &time))
+ if (Interop.Kernel32.FileTimeToSystemTime(&fileTime, &time.systemTime) == Interop.BOOL.FALSE)
{
- return CreateDateTimeFromSystemTime(in time);
+ throw new ArgumentOutOfRangeException(nameof(fileTime), SR.ArgumentOutOfRange_DateTimeBadTicks);
}
- throw new ArgumentOutOfRangeException(nameof(fileTime), SR.ArgumentOutOfRange_DateTimeBadTicks);
+ // 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 CreateDateTimeFromSystemTime(in time);
}
private static unsafe long ToFileTimeLeapSecondsAware(long ticks)
@@ -54,12 +98,12 @@ private static unsafe long ToFileTimeLeapSecondsAware(long ticks)
FullSystemTime time = new FullSystemTime(ticks);
long fileTime;
- if (SystemTimeToFileTime(&time.systemTime, &fileTime))
+ if (Interop.Kernel32.SystemTimeToFileTime(&time.systemTime, &fileTime) == Interop.BOOL.FALSE)
{
- return fileTime + ticks % TicksPerMillisecond;
+ throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_FileTimeInvalid);
}
- throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_FileTimeInvalid);
+ return fileTime + ticks % TicksPerMillisecond;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -111,12 +155,14 @@ internal FullSystemTime(long ticks)
}
}
-#if !CORECLR
- internal static readonly bool s_systemSupportsPreciseSystemTime = SystemSupportsPreciseSystemTime();
+ private static unsafe readonly delegate* unmanaged[SuppressGCTransition] s_pfnGetSystemTimeAsFileTime = GetGetSystemTimeAsFileTimeFnPtr();
- private static unsafe bool SystemSupportsPreciseSystemTime()
+ private static unsafe delegate* unmanaged[SuppressGCTransition] GetGetSystemTimeAsFileTimeFnPtr()
{
- if (Environment.IsWindows8OrAbove)
+ IntPtr kernel32Lib = NativeLibrary.Load("kernel32.dll", typeof(DateTime).Assembly, DllImportSearchPath.System32);
+ IntPtr pfnGetSystemTime = NativeLibrary.GetExport(kernel32Lib, "GetSystemTimeAsFileTime");
+
+ if (NativeLibrary.TryGetExport(kernel32Lib, "GetSystemTimePreciseAsFileTime", out IntPtr pfnGetSystemTimePrecise))
{
// GetSystemTimePreciseAsFileTime exists and we'd like to use it. However, on
// misconfigured systems, it's possible for the "precise" time to be inaccurate:
@@ -127,88 +173,23 @@ private static unsafe bool SystemSupportsPreciseSystemTime()
// 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)
+ // Retry this check several times to reduce chance of false negatives due to thread being rescheduled
+ // at wrong time.
+ for (int i = 0; i < 10; i++)
{
- // 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;
+ long systemTimeResult, preciseSystemTimeResult;
+ ((delegate* unmanaged[SuppressGCTransition])pfnGetSystemTime)(&systemTimeResult);
+ ((delegate* unmanaged[SuppressGCTransition])pfnGetSystemTimePrecise)(&preciseSystemTimeResult);
+
+ if (Math.Abs(preciseSystemTimeResult - systemTimeResult) <= 100 * TicksPerMillisecond)
+ {
+ pfnGetSystemTime = pfnGetSystemTimePrecise; // use the precise version
+ break;
+ }
}
}
- }
-
- 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;
+ return (delegate* unmanaged[SuppressGCTransition])pfnGetSystemTime;
}
-#endif
}
}