Fix StyleCop warning SA1006 (empty statements)
[mono-project.git] / netcore / System.Private.CoreLib / shared / System / DateTime.Windows.cs
blob7628d339bda584a19da29fdc4bfa6b37d1186a3d
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 using System.Runtime.CompilerServices;
6 using System.Runtime.InteropServices;
8 namespace System
10 public readonly partial struct DateTime
12 internal static readonly bool s_systemSupportsLeapSeconds = SystemSupportsLeapSeconds();
14 public static unsafe DateTime UtcNow
16 get
18 if (s_systemSupportsLeapSeconds)
20 FullSystemTime time;
21 GetSystemTimeWithLeapSecondsHandling(&time);
22 return CreateDateTimeFromSystemTime(in time);
25 return new DateTime(((ulong)(GetSystemTimeAsFileTime() + FileTimeOffset)) | KindUtc);
29 internal static unsafe bool IsValidTimeWithLeapSeconds(int year, int month, int day, int hour, int minute, int second, DateTimeKind kind)
31 DateTime dt = new DateTime(year, month, day);
32 FullSystemTime time = new FullSystemTime(year, month, dt.DayOfWeek, day, hour, minute, second);
34 return kind switch
36 DateTimeKind.Local => ValidateSystemTime(&time.systemTime, localTime: true),
37 DateTimeKind.Utc => ValidateSystemTime(&time.systemTime, localTime: false),
38 _ => ValidateSystemTime(&time.systemTime, localTime: true) || ValidateSystemTime(&time.systemTime, localTime: false),
42 private static unsafe DateTime FromFileTimeLeapSecondsAware(long fileTime)
44 FullSystemTime time;
45 if (FileTimeToSystemTime(fileTime, &time))
47 return CreateDateTimeFromSystemTime(in time);
50 throw new ArgumentOutOfRangeException(nameof(fileTime), SR.ArgumentOutOfRange_DateTimeBadTicks);
53 private static unsafe long ToFileTimeLeapSecondsAware(long ticks)
55 FullSystemTime time = new FullSystemTime(ticks);
56 long fileTime;
58 if (SystemTimeToFileTime(&time.systemTime, &fileTime))
60 return fileTime + ticks % TicksPerMillisecond;
63 throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_FileTimeInvalid);
66 [MethodImpl(MethodImplOptions.AggressiveInlining)]
67 private static DateTime CreateDateTimeFromSystemTime(in FullSystemTime time)
69 long ticks = DateToTicks(time.systemTime.Year, time.systemTime.Month, time.systemTime.Day);
70 ticks += TimeToTicks(time.systemTime.Hour, time.systemTime.Minute, time.systemTime.Second);
71 ticks += time.systemTime.Milliseconds * TicksPerMillisecond;
72 ticks += time.hundredNanoSecond;
73 return new DateTime(((ulong)(ticks)) | KindUtc);
76 // FullSystemTime struct is the SYSTEMTIME struct with extra hundredNanoSecond field to store more precise time.
77 [StructLayout(LayoutKind.Sequential)]
78 private struct FullSystemTime
80 internal Interop.Kernel32.SYSTEMTIME systemTime;
81 internal long hundredNanoSecond;
83 internal FullSystemTime(int year, int month, DayOfWeek dayOfWeek, int day, int hour, int minute, int second)
85 systemTime.Year = (ushort)year;
86 systemTime.Month = (ushort)month;
87 systemTime.DayOfWeek = (ushort)dayOfWeek;
88 systemTime.Day = (ushort)day;
89 systemTime.Hour = (ushort)hour;
90 systemTime.Minute = (ushort)minute;
91 systemTime.Second = (ushort)second;
92 systemTime.Milliseconds = 0;
93 hundredNanoSecond = 0;
96 internal FullSystemTime(long ticks)
98 DateTime dt = new DateTime(ticks);
100 int year, month, day;
101 dt.GetDatePart(out year, out month, out day);
103 systemTime.Year = (ushort)year;
104 systemTime.Month = (ushort)month;
105 systemTime.DayOfWeek = (ushort)dt.DayOfWeek;
106 systemTime.Day = (ushort)day;
107 systemTime.Hour = (ushort)dt.Hour;
108 systemTime.Minute = (ushort)dt.Minute;
109 systemTime.Second = (ushort)dt.Second;
110 systemTime.Milliseconds = (ushort)dt.Millisecond;
111 hundredNanoSecond = 0;
115 #if !CORECLR
116 internal static readonly bool s_systemSupportsPreciseSystemTime = SystemSupportsPreciseSystemTime();
118 private static unsafe bool SystemSupportsPreciseSystemTime()
120 if (Environment.IsWindows8OrAbove)
122 // GetSystemTimePreciseAsFileTime exists and we'd like to use it. However, on
123 // misconfigured systems, it's possible for the "precise" time to be inaccurate:
124 // https://github.com/dotnet/coreclr/issues/14187
125 // If it's inaccurate, though, we expect it to be wildly inaccurate, so as a
126 // workaround/heuristic, we get both the "normal" and "precise" times, and as
127 // long as they're close, we use the precise one. This workaround can be removed
128 // when we better understand what's causing the drift and the issue is no longer
129 // a problem or can be better worked around on all targeted OSes.
131 long systemTimeResult;
132 Interop.Kernel32.GetSystemTimeAsFileTime(&systemTimeResult);
134 long preciseSystemTimeResult;
135 Interop.Kernel32.GetSystemTimePreciseAsFileTime(&preciseSystemTimeResult);
137 return Math.Abs(preciseSystemTimeResult - systemTimeResult) <= 100 * TicksPerMillisecond;
140 return false;
143 private static unsafe bool ValidateSystemTime(Interop.Kernel32.SYSTEMTIME* time, bool localTime)
145 if (localTime)
147 Interop.Kernel32.SYSTEMTIME st;
148 return Interop.Kernel32.TzSpecificLocalTimeToSystemTime(IntPtr.Zero, time, &st) != Interop.BOOL.FALSE;
150 else
152 long timestamp;
153 return Interop.Kernel32.SystemTimeToFileTime(time, &timestamp) != Interop.BOOL.FALSE;
157 private static unsafe bool FileTimeToSystemTime(long fileTime, FullSystemTime* time)
159 if (Interop.Kernel32.FileTimeToSystemTime(&fileTime, &time->systemTime) != Interop.BOOL.FALSE)
161 // to keep the time precision
162 time->hundredNanoSecond = fileTime % TicksPerMillisecond;
163 if (time->systemTime.Second > 59)
165 // we have a leap second, force it to last second in the minute as DateTime doesn't account for leap seconds in its calculation.
166 // we use the maxvalue from the milliseconds and the 100-nano seconds to avoid reporting two out of order 59 seconds
167 time->systemTime.Second = 59;
168 time->systemTime.Milliseconds = 999;
169 time->hundredNanoSecond = 9999;
171 return true;
173 return false;
176 private static unsafe void GetSystemTimeWithLeapSecondsHandling(FullSystemTime* time)
178 if (!FileTimeToSystemTime(GetSystemTimeAsFileTime(), time))
180 Interop.Kernel32.GetSystemTime(&time->systemTime);
181 time->hundredNanoSecond = 0;
182 if (time->systemTime.Second > 59)
184 // we have a leap second, force it to last second in the minute as DateTime doesn't account for leap seconds in its calculation.
185 // we use the maxvalue from the milliseconds and the 100-nano seconds to avoid reporting two out of order 59 seconds
186 time->systemTime.Second = 59;
187 time->systemTime.Milliseconds = 999;
188 time->hundredNanoSecond = 9999;
193 private static unsafe bool SystemTimeToFileTime(Interop.Kernel32.SYSTEMTIME* time, long* fileTime)
195 return Interop.Kernel32.SystemTimeToFileTime(time, fileTime) != Interop.BOOL.FALSE;
198 private static unsafe long GetSystemTimeAsFileTime()
200 long timestamp;
202 if (s_systemSupportsPreciseSystemTime)
204 Interop.Kernel32.GetSystemTimePreciseAsFileTime(&timestamp);
206 else
208 Interop.Kernel32.GetSystemTimeAsFileTime(&timestamp);
211 return timestamp;
213 #endif