Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
/corefxPublic archive

Commitd7925a7

Browse files
tarekghstephentoub
authored andcommitted
Leap Seconds Support (dotnet/coreclr#21420)
* Leap Seconds Support* Address Feedback* More feedback addressingSigned-off-by: dotnet-bot <dotnet-bot@microsoft.com>
1 parent5ce17d9 commitd7925a7

File tree

4 files changed

+196
-12
lines changed

4 files changed

+196
-12
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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.
4+
5+
usingSystem;
6+
usingSystem.Runtime.InteropServices;
7+
8+
internalpartialclassInterop
9+
{
10+
internalpartialclassNtDll
11+
{
12+
[DllImport(Libraries.NtDll)]
13+
internalstaticunsafeexternintNtQuerySystemInformation(intSystemInformationClass,void*SystemInformation,intSystemInformationLength,uint*ReturnLength);
14+
15+
[StructLayout(LayoutKind.Sequential)]
16+
internalstructSYSTEM_LEAP_SECOND_INFORMATION
17+
{
18+
publicboolEnabled;
19+
publicuintFlags;
20+
}
21+
22+
internalconstintSystemLeapSecondInformation=206;
23+
}
24+
}

‎src/Common/src/CoreLib/System.Private.CoreLib.Shared.projitems‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,7 @@
859859
<CompileInclude="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs" />
860860
<CompileInclude="$(MSBuildThisFileDirectory)Interop\Windows\Normaliz\Interop.Idna.cs"Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
861861
<CompileInclude="$(MSBuildThisFileDirectory)Interop\Windows\Normaliz\Interop.Normalization.cs"Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
862+
<CompileInclude="$(MSBuildThisFileDirectory)Interop\Windows\NtDll\Interop.NtQuerySystemInformation.cs"Condition="'$(EnableWinRT)' != 'true'" />
862863
<CompileInclude="$(MSBuildThisFileDirectory)Interop\Windows\Ole32\Interop.CoCreateGuid.cs" />
863864
<CompileInclude="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysAllocStringLen.cs" />
864865
<CompileInclude="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysFreeString.cs" />

‎src/Common/src/CoreLib/System/DateTime.cs‎

Lines changed: 120 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,14 @@ public DateTime(int year, int month, int day, Calendar calendar)
196196
//
197197
publicDateTime(intyear,intmonth,intday,inthour,intminute,intsecond)
198198
{
199+
if(second==60&&s_systemSupportsLeapSeconds&&IsValidTimeWithLeapSeconds(year,month,day,hour,minute,second,DateTimeKind.Unspecified))
200+
{
201+
// if we have leap second (second = 60) then we'll need to check if it is valid time.
202+
// if it is valid, then we adjust the second to 59 so DateTime will consider this second is last second
203+
// in the specified minute.
204+
// if it is not valid time, we'll eventually throw.
205+
second=59;
206+
}
199207
_dateData=(ulong)(DateToTicks(year,month,day)+TimeToTicks(hour,minute,second));
200208
}
201209

@@ -205,6 +213,16 @@ public DateTime(int year, int month, int day, int hour, int minute, int second,
205213
{
206214
thrownewArgumentException(SR.Argument_InvalidDateTimeKind,nameof(kind));
207215
}
216+
217+
if(second==60&&s_systemSupportsLeapSeconds&&IsValidTimeWithLeapSeconds(year,month,day,hour,minute,second,kind))
218+
{
219+
// if we have leap second (second = 60) then we'll need to check if it is valid time.
220+
// if it is valid, then we adjust the second to 59 so DateTime will consider this second is last second
221+
// in the specified minute.
222+
// if it is not valid time, we'll eventually throw.
223+
second=59;
224+
}
225+
208226
longticks=DateToTicks(year,month,day)+TimeToTicks(hour,minute,second);
209227
_dateData=((ulong)ticks|((ulong)kind<<KindShift));
210228
}
@@ -216,7 +234,24 @@ public DateTime(int year, int month, int day, int hour, int minute, int second,
216234
{
217235
if(calendar==null)
218236
thrownewArgumentNullException(nameof(calendar));
237+
238+
intoriginalSecond=second;
239+
if(second==60&&s_systemSupportsLeapSeconds)
240+
{
241+
// Reset the second value now and then we'll validate it later when we get the final Gregorian date.
242+
second=59;
243+
}
244+
219245
_dateData=(ulong)calendar.ToDateTime(year,month,day,hour,minute,second,0).Ticks;
246+
247+
if(originalSecond==60)
248+
{
249+
DateTimedt=newDateTime(_dateData);
250+
if(!IsValidTimeWithLeapSeconds(dt.Year,dt.Month,dt.Day,dt.Hour,dt.Minute,60,DateTimeKind.Unspecified))
251+
{
252+
thrownewArgumentOutOfRangeException(null,SR.ArgumentOutOfRange_BadHourMinuteSecond);
253+
}
254+
}
220255
}
221256

222257
// Constructs a DateTime from a given year, month, day, hour,
@@ -228,6 +263,16 @@ public DateTime(int year, int month, int day, int hour, int minute, int second,
228263
{
229264
thrownewArgumentOutOfRangeException(nameof(millisecond),SR.Format(SR.ArgumentOutOfRange_Range,0,MillisPerSecond-1));
230265
}
266+
267+
if(second==60&&s_systemSupportsLeapSeconds&&IsValidTimeWithLeapSeconds(year,month,day,hour,minute,second,DateTimeKind.Unspecified))
268+
{
269+
// if we have leap second (second = 60) then we'll need to check if it is valid time.
270+
// if it is valid, then we adjust the second to 59 so DateTime will consider this second is last second
271+
// in the specified minute.
272+
// if it is not valid time, we'll eventually throw.
273+
second=59;
274+
}
275+
231276
longticks=DateToTicks(year,month,day)+TimeToTicks(hour,minute,second);
232277
ticks+=millisecond*TicksPerMillisecond;
233278
if(ticks<MinTicks||ticks>MaxTicks)
@@ -245,6 +290,16 @@ public DateTime(int year, int month, int day, int hour, int minute, int second,
245290
{
246291
thrownewArgumentException(SR.Argument_InvalidDateTimeKind,nameof(kind));
247292
}
293+
294+
if(second==60&&s_systemSupportsLeapSeconds&&IsValidTimeWithLeapSeconds(year,month,day,hour,minute,second,kind))
295+
{
296+
// if we have leap second (second = 60) then we'll need to check if it is valid time.
297+
// if it is valid, then we adjust the second to 59 so DateTime will consider this second is last second
298+
// in the specified minute.
299+
// if it is not valid time, we'll eventually throw.
300+
second=59;
301+
}
302+
248303
longticks=DateToTicks(year,month,day)+TimeToTicks(hour,minute,second);
249304
ticks+=millisecond*TicksPerMillisecond;
250305
if(ticks<MinTicks||ticks>MaxTicks)
@@ -263,11 +318,28 @@ public DateTime(int year, int month, int day, int hour, int minute, int second,
263318
{
264319
thrownewArgumentOutOfRangeException(nameof(millisecond),SR.Format(SR.ArgumentOutOfRange_Range,0,MillisPerSecond-1));
265320
}
321+
322+
intoriginalSecond=second;
323+
if(second==60&&s_systemSupportsLeapSeconds)
324+
{
325+
// Reset the second value now and then we'll validate it later when we get the final Gregorian date.
326+
second=59;
327+
}
328+
266329
longticks=calendar.ToDateTime(year,month,day,hour,minute,second,0).Ticks;
267330
ticks+=millisecond*TicksPerMillisecond;
268331
if(ticks<MinTicks||ticks>MaxTicks)
269332
thrownewArgumentException(SR.Arg_DateTimeRange);
270333
_dateData=(ulong)ticks;
334+
335+
if(originalSecond==60)
336+
{
337+
DateTimedt=newDateTime(_dateData);
338+
if(!IsValidTimeWithLeapSeconds(dt.Year,dt.Month,dt.Day,dt.Hour,dt.Minute,60,DateTimeKind.Unspecified))
339+
{
340+
thrownewArgumentOutOfRangeException(null,SR.ArgumentOutOfRange_BadHourMinuteSecond);
341+
}
342+
}
271343
}
272344

273345
publicDateTime(intyear,intmonth,intday,inthour,intminute,intsecond,intmillisecond,Calendarcalendar,DateTimeKindkind)
@@ -282,11 +354,28 @@ public DateTime(int year, int month, int day, int hour, int minute, int second,
282354
{
283355
thrownewArgumentException(SR.Argument_InvalidDateTimeKind,nameof(kind));
284356
}
357+
358+
intoriginalSecond=second;
359+
if(second==60&&s_systemSupportsLeapSeconds)
360+
{
361+
// Reset the second value now and then we'll validate it later when we get the final Gregorian date.
362+
second=59;
363+
}
364+
285365
longticks=calendar.ToDateTime(year,month,day,hour,minute,second,0).Ticks;
286366
ticks+=millisecond*TicksPerMillisecond;
287367
if(ticks<MinTicks||ticks>MaxTicks)
288368
thrownewArgumentException(SR.Arg_DateTimeRange);
289369
_dateData=((ulong)ticks|((ulong)kind<<KindShift));
370+
371+
if(originalSecond==60)
372+
{
373+
DateTimedt=newDateTime(_dateData);
374+
if(!IsValidTimeWithLeapSeconds(dt.Year,dt.Month,dt.Day,dt.Hour,dt.Minute,60,kind))
375+
{
376+
thrownewArgumentOutOfRangeException(null,SR.ArgumentOutOfRange_BadHourMinuteSecond);
377+
}
378+
}
290379
}
291380

292381
privateDateTime(SerializationInfoinfo,StreamingContextcontext)
@@ -338,8 +427,6 @@ private DateTime(SerializationInfo info, StreamingContext context)
338427
}
339428
}
340429

341-
342-
343430
internallongInternalTicks
344431
{
345432
get
@@ -722,6 +809,11 @@ public static DateTime FromFileTimeUtc(long fileTime)
722809
thrownewArgumentOutOfRangeException(nameof(fileTime),SR.ArgumentOutOfRange_FileTimeInvalid);
723810
}
724811

812+
if(s_systemSupportsLeapSeconds)
813+
{
814+
returnFromFileTimeLeapSecondsAware(fileTime);
815+
}
816+
725817
// This is the ticks in Universal time for this fileTime.
726818
longuniversalTicks=fileTime+FileTimeOffset;
727819
returnnewDateTime(universalTicks,DateTimeKind.Utc);
@@ -1223,11 +1315,18 @@ public long ToFileTimeUtc()
12231315
{
12241316
// Treats the input as universal if it is not specified
12251317
longticks=((InternalKind&LocalMask)!=0)?ToUniversalTime().InternalTicks:this.InternalTicks;
1318+
1319+
if(s_systemSupportsLeapSeconds)
1320+
{
1321+
returnToFileTimeLeapSecondsAware(ticks);
1322+
}
1323+
12261324
ticks-=FileTimeOffset;
12271325
if(ticks<0)
12281326
{
12291327
thrownewArgumentOutOfRangeException(null,SR.ArgumentOutOfRange_FileTimeInvalid);
12301328
}
1329+
12311330
returnticks;
12321331
}
12331332

@@ -1574,14 +1673,32 @@ internal static bool TryCreate(int year, int month, int day, int hour, int minut
15741673
{
15751674
returnfalse;
15761675
}
1577-
if(hour<0||hour>=24||minute<0||minute>=60||second<0||second>=60)
1676+
if(hour<0||hour>=24||minute<0||minute>=60||second<0||second>60)
15781677
{
15791678
returnfalse;
15801679
}
15811680
if(millisecond<0||millisecond>=MillisPerSecond)
15821681
{
15831682
returnfalse;
15841683
}
1684+
1685+
if(second==60)
1686+
{
1687+
if(s_systemSupportsLeapSeconds&&IsValidTimeWithLeapSeconds(year,month,day,hour,minute,second,DateTimeKind.Unspecified))
1688+
{
1689+
// if we have leap second (second = 60) then we'll need to check if it is valid time.
1690+
// if it is valid, then we adjust the second to 59 so DateTime will consider this second is last second
1691+
// of this minute.
1692+
// if it is not valid time, we'll eventually throw.
1693+
// although this is unspecified datetime kind, we'll assume the passed time is UTC to check the leap seconds.
1694+
second=59;
1695+
}
1696+
else
1697+
{
1698+
returnfalse;
1699+
}
1700+
}
1701+
15851702
longticks=DateToTicks(year,month,day)+TimeToTicks(hour,minute,second);
15861703

15871704
ticks+=millisecond*TicksPerMillisecond;

‎src/Common/src/CoreLib/System/DateTimeOffset.cs‎

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99

1010
namespaceSystem
1111
{
12-
// DateTimeOffset is a value type that consists of a DateTime and a time zone offset,
12+
// DateTimeOffset is a value type that consists of a DateTime and a time zone offset,
1313
// ie. how far away the time is from GMT. The DateTime is stored whole, and the offset
14-
// is stored as an Int16 internally to save space, but presented as a TimeSpan.
14+
// is stored as an Int16 internally to save space, but presented as a TimeSpan.
1515
//
1616
// The range is constrained so that both the represented clock time and the represented
1717
// UTC time fit within the boundaries of MaxValue. This gives it the same range as DateTime
1818
// for actual UTC times, and a slightly constrained range on one end when an offset is
19-
// present.
19+
// present.
2020
//
2121
// This class should be substitutable for date time in most cases; so most operations
2222
// effectively work on the clock time. However, the underlying UTC time is what counts
@@ -30,7 +30,7 @@ namespace System
3030

3131
[StructLayout(LayoutKind.Auto)]
3232
[Serializable]
33-
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
33+
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
3434
publicreadonlystructDateTimeOffset:IComparable,IFormattable,IComparable<DateTimeOffset>,IEquatable<DateTimeOffset>,ISerializable,IDeserializationCallback,ISpanFormattable
3535
{
3636
// Constants
@@ -109,23 +109,65 @@ public DateTimeOffset(DateTime dateTime, TimeSpan offset)
109109
publicDateTimeOffset(intyear,intmonth,intday,inthour,intminute,intsecond,TimeSpanoffset)
110110
{
111111
_offsetMinutes=ValidateOffset(offset);
112+
113+
intoriginalSecond=second;
114+
if(second==60&&DateTime.s_systemSupportsLeapSeconds)
115+
{
116+
// Reset the leap second to 59 for now and then we'll validate it after getting the final UTC time.
117+
second=59;
118+
}
119+
112120
_dateTime=ValidateDate(newDateTime(year,month,day,hour,minute,second),offset);
121+
122+
if(originalSecond==60&&
123+
!DateTime.IsValidTimeWithLeapSeconds(_dateTime.Year,_dateTime.Month,_dateTime.Day,_dateTime.Hour,_dateTime.Minute,60,DateTimeKind.Utc))
124+
{
125+
thrownewArgumentOutOfRangeException(null,SR.ArgumentOutOfRange_BadHourMinuteSecond);
126+
}
113127
}
114128

115129
// Constructs a DateTimeOffset from a given year, month, day, hour,
116130
// minute, second, millsecond and offset
117131
publicDateTimeOffset(intyear,intmonth,intday,inthour,intminute,intsecond,intmillisecond,TimeSpanoffset)
118132
{
119133
_offsetMinutes=ValidateOffset(offset);
134+
135+
intoriginalSecond=second;
136+
if(second==60&&DateTime.s_systemSupportsLeapSeconds)
137+
{
138+
// Reset the leap second to 59 for now and then we'll validate it after getting the final UTC time.
139+
second=59;
140+
}
141+
120142
_dateTime=ValidateDate(newDateTime(year,month,day,hour,minute,second,millisecond),offset);
143+
144+
if(originalSecond==60&&
145+
!DateTime.IsValidTimeWithLeapSeconds(_dateTime.Year,_dateTime.Month,_dateTime.Day,_dateTime.Hour,_dateTime.Minute,60,DateTimeKind.Utc))
146+
{
147+
thrownewArgumentOutOfRangeException(null,SR.ArgumentOutOfRange_BadHourMinuteSecond);
148+
}
121149
}
122150

123151
// Constructs a DateTimeOffset from a given year, month, day, hour,
124152
// minute, second, millsecond, Calendar and offset.
125153
publicDateTimeOffset(intyear,intmonth,intday,inthour,intminute,intsecond,intmillisecond,Calendarcalendar,TimeSpanoffset)
126154
{
127155
_offsetMinutes=ValidateOffset(offset);
156+
157+
intoriginalSecond=second;
158+
if(second==60&&DateTime.s_systemSupportsLeapSeconds)
159+
{
160+
// Reset the leap second to 59 for now and then we'll validate it after getting the final UTC time.
161+
second=59;
162+
}
163+
128164
_dateTime=ValidateDate(newDateTime(year,month,day,hour,minute,second,millisecond,calendar),offset);
165+
166+
if(originalSecond==60&&
167+
!DateTime.IsValidTimeWithLeapSeconds(_dateTime.Year,_dateTime.Month,_dateTime.Day,_dateTime.Hour,_dateTime.Minute,60,DateTimeKind.Utc))
168+
{
169+
thrownewArgumentOutOfRangeException(null,SR.ArgumentOutOfRange_BadHourMinuteSecond);
170+
}
129171
}
130172

131173
// Returns a DateTimeOffset representing the current date and time. The
@@ -596,7 +638,7 @@ public override int GetHashCode()
596638
// Constructs a DateTimeOffset from a string. The string must specify a
597639
// date and optionally a time in a culture-specific or universal format.
598640
// Leading and trailing whitespace characters are allowed.
599-
//
641+
//
600642
publicstaticDateTimeOffsetParse(stringinput)
601643
{
602644
if(input==null)ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
@@ -612,7 +654,7 @@ public static DateTimeOffset Parse(string input)
612654
// Constructs a DateTimeOffset from a string. The string must specify a
613655
// date and optionally a time in a culture-specific or universal format.
614656
// Leading and trailing whitespace characters are allowed.
615-
//
657+
//
616658
publicstaticDateTimeOffsetParse(stringinput,IFormatProviderformatProvider)
617659
{
618660
if(input==null)ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
@@ -642,7 +684,7 @@ public static DateTimeOffset Parse(ReadOnlySpan<char> input, IFormatProvider for
642684
// Constructs a DateTimeOffset from a string. The string must specify a
643685
// date and optionally a time in a culture-specific or universal format.
644686
// Leading and trailing whitespace characters are allowed.
645-
//
687+
//
646688
publicstaticDateTimeOffsetParseExact(stringinput,stringformat,IFormatProviderformatProvider)
647689
{
648690
if(input==null)ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
@@ -653,7 +695,7 @@ public static DateTimeOffset ParseExact(string input, string format, IFormatProv
653695
// Constructs a DateTimeOffset from a string. The string must specify a
654696
// date and optionally a time in a culture-specific or universal format.
655697
// Leading and trailing whitespace characters are allowed.
656-
//
698+
//
657699
publicstaticDateTimeOffsetParseExact(stringinput,stringformat,IFormatProviderformatProvider,DateTimeStylesstyles)
658700
{
659701
styles=ValidateStyles(styles,nameof(styles));
@@ -943,7 +985,7 @@ private static DateTimeStyles ValidateStyles(DateTimeStyles style, string parame
943985
// RoundtripKind does not make sense for DateTimeOffset; ignore this flag for backward compatibility with DateTime
944986
style&=~DateTimeStyles.RoundtripKind;
945987

946-
// AssumeLocal is also ignored as that is what we do by default with DateTimeOffset.Parse
988+
// AssumeLocal is also ignored as that is what we do by default with DateTimeOffset.Parse
947989
style&=~DateTimeStyles.AssumeLocal;
948990

949991
returnstyle;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp