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 using System;
6 using System.Diagnostics;
7 using System.Threading;
8 using System.Globalization;
9 using System.Runtime;
10 using System.Runtime.InteropServices;
11 using System.Runtime.CompilerServices;
12 using System.Runtime.Serialization;
13 using System.Runtime.Versioning;
14 using System.Security;
15 using CultureInfo = System.Globalization.CultureInfo;
16 using Calendar = System.Globalization.Calendar;
17 
18 namespace System
19 {
20     // This value type represents a date and time.  Every DateTime
21     // object has a private field (Ticks) of type Int64 that stores the
22     // date and time as the number of 100 nanosecond intervals since
23     // 12:00 AM January 1, year 1 A.D. in the proleptic Gregorian Calendar.
24     //
25     // Starting from V2.0, DateTime also stored some context about its time
26     // zone in the form of a 3-state value representing Unspecified, Utc or
27     // Local. This is stored in the two top bits of the 64-bit numeric value
28     // with the remainder of the bits storing the tick count. This information
29     // is only used during time zone conversions and is not part of the
30     // identity of the DateTime. Thus, operations like Compare and Equals
31     // ignore this state. This is to stay compatible with earlier behavior
32     // and performance characteristics and to avoid forcing  people into dealing
33     // with the effects of daylight savings. Note, that this has little effect
34     // on how the DateTime works except in a context where its specific time
35     // zone is needed, such as during conversions and some parsing and formatting
36     // cases.
37     //
38     // There is also 4th state stored that is a special type of Local value that
39     // is used to avoid data loss when round-tripping between local and UTC time.
40     // See below for more information on this 4th state, although it is
41     // effectively hidden from most users, who just see the 3-state DateTimeKind
42     // enumeration.
43     //
44     // For compatibility, DateTime does not serialize the Kind data when used in
45     // binary serialization.
46     //
47     // For a description of various calendar issues, look at
48     //
49     // Calendar Studies web site, at
50     // http://serendipity.nofadz.com/hermetic/cal_stud.htm.
51     //
52     //
53     [StructLayout(LayoutKind.Auto)]
54     [Serializable]
55     [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
56     public readonly partial struct DateTime : IComparable, IFormattable, IConvertible, IComparable<DateTime>, IEquatable<DateTime>, ISerializable, ISpanFormattable
57     {
58         // Number of 100ns ticks per time unit
59         private const long TicksPerMillisecond = 10000;
60         private const long TicksPerSecond = TicksPerMillisecond * 1000;
61         private const long TicksPerMinute = TicksPerSecond * 60;
62         private const long TicksPerHour = TicksPerMinute * 60;
63         private const long TicksPerDay = TicksPerHour * 24;
64 
65         // Number of milliseconds per time unit
66         private const int MillisPerSecond = 1000;
67         private const int MillisPerMinute = MillisPerSecond * 60;
68         private const int MillisPerHour = MillisPerMinute * 60;
69         private const int MillisPerDay = MillisPerHour * 24;
70 
71         // Number of days in a non-leap year
72         private const int DaysPerYear = 365;
73         // Number of days in 4 years
74         private const int DaysPer4Years = DaysPerYear * 4 + 1;       // 1461
75         // Number of days in 100 years
76         private const int DaysPer100Years = DaysPer4Years * 25 - 1;  // 36524
77         // Number of days in 400 years
78         private const int DaysPer400Years = DaysPer100Years * 4 + 1; // 146097
79 
80         // Number of days from 1/1/0001 to 12/31/1600
81         private const int DaysTo1601 = DaysPer400Years * 4;          // 584388
82         // Number of days from 1/1/0001 to 12/30/1899
83         private const int DaysTo1899 = DaysPer400Years * 4 + DaysPer100Years * 3 - 367;
84         // Number of days from 1/1/0001 to 12/31/1969
85         internal const int DaysTo1970 = DaysPer400Years * 4 + DaysPer100Years * 3 + DaysPer4Years * 17 + DaysPerYear; // 719,162
86         // Number of days from 1/1/0001 to 12/31/9999
87         private const int DaysTo10000 = DaysPer400Years * 25 - 366;  // 3652059
88 
89         internal const long MinTicks = 0;
90         internal const long MaxTicks = DaysTo10000 * TicksPerDay - 1;
91         private const long MaxMillis = (long)DaysTo10000 * MillisPerDay;
92 
93         internal const long UnixEpochTicks = DaysTo1970 * TicksPerDay;
94         private const long FileTimeOffset = DaysTo1601 * TicksPerDay;
95         private const long DoubleDateOffset = DaysTo1899 * TicksPerDay;
96         // The minimum OA date is 0100/01/01 (Note it's year 100).
97         // The maximum OA date is 9999/12/31
98         private const long OADateMinAsTicks = (DaysPer100Years - DaysPerYear) * TicksPerDay;
99         // All OA dates must be greater than (not >=) OADateMinAsDouble
100         private const double OADateMinAsDouble = -657435.0;
101         // All OA dates must be less than (not <=) OADateMaxAsDouble
102         private const double OADateMaxAsDouble = 2958466.0;
103 
104         private const int DatePartYear = 0;
105         private const int DatePartDayOfYear = 1;
106         private const int DatePartMonth = 2;
107         private const int DatePartDay = 3;
108 
109         private static readonly int[] s_daysToMonth365 = {
110             0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
111         private static readonly int[] s_daysToMonth366 = {
112             0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366};
113 
114         public static readonly DateTime MinValue = new DateTime(MinTicks, DateTimeKind.Unspecified);
115         public static readonly DateTime MaxValue = new DateTime(MaxTicks, DateTimeKind.Unspecified);
116         public static readonly DateTime UnixEpoch = new DateTime(UnixEpochTicks, DateTimeKind.Utc);
117 
118         private const UInt64 TicksMask = 0x3FFFFFFFFFFFFFFF;
119         private const UInt64 FlagsMask = 0xC000000000000000;
120         private const UInt64 LocalMask = 0x8000000000000000;
121         private const Int64 TicksCeiling = 0x4000000000000000;
122         private const UInt64 KindUnspecified = 0x0000000000000000;
123         private const UInt64 KindUtc = 0x4000000000000000;
124         private const UInt64 KindLocal = 0x8000000000000000;
125         private const UInt64 KindLocalAmbiguousDst = 0xC000000000000000;
126         private const Int32 KindShift = 62;
127 
128         private const String TicksField = "ticks"; // Do not rename (binary serialization)
129         private const String DateDataField = "dateData"; // Do not rename (binary serialization)
130 
131         // The data is stored as an unsigned 64-bit integer
132         //   Bits 01-62: The value of 100-nanosecond ticks where 0 represents 1/1/0001 12:00am, up until the value
133         //               12/31/9999 23:59:59.9999999
134         //   Bits 63-64: A four-state value that describes the DateTimeKind value of the date time, with a 2nd
135         //               value for the rare case where the date time is local, but is in an overlapped daylight
136         //               savings time hour and it is in daylight savings time. This allows distinction of these
137         //               otherwise ambiguous local times and prevents data loss when round tripping from Local to
138         //               UTC time.
139         private readonly UInt64 _dateData;
140 
141         // Constructs a DateTime from a tick count. The ticks
142         // argument specifies the date as the number of 100-nanosecond intervals
143         // that have elapsed since 1/1/0001 12:00am.
144         //
DateTimeSystem.DateTime145         public DateTime(long ticks)
146         {
147             if (ticks < MinTicks || ticks > MaxTicks)
148                 throw new ArgumentOutOfRangeException(nameof(ticks), SR.ArgumentOutOfRange_DateTimeBadTicks);
149             _dateData = (UInt64)ticks;
150         }
151 
DateTimeSystem.DateTime152         private DateTime(UInt64 dateData)
153         {
154             this._dateData = dateData;
155         }
156 
DateTimeSystem.DateTime157         public DateTime(long ticks, DateTimeKind kind)
158         {
159             if (ticks < MinTicks || ticks > MaxTicks)
160             {
161                 throw new ArgumentOutOfRangeException(nameof(ticks), SR.ArgumentOutOfRange_DateTimeBadTicks);
162             }
163             if (kind < DateTimeKind.Unspecified || kind > DateTimeKind.Local)
164             {
165                 throw new ArgumentException(SR.Argument_InvalidDateTimeKind, nameof(kind));
166             }
167             _dateData = ((UInt64)ticks | ((UInt64)kind << KindShift));
168         }
169 
DateTimeSystem.DateTime170         internal DateTime(long ticks, DateTimeKind kind, Boolean isAmbiguousDst)
171         {
172             if (ticks < MinTicks || ticks > MaxTicks)
173             {
174                 throw new ArgumentOutOfRangeException(nameof(ticks), SR.ArgumentOutOfRange_DateTimeBadTicks);
175             }
176             Debug.Assert(kind == DateTimeKind.Local, "Internal Constructor is for local times only");
177             _dateData = ((UInt64)ticks | (isAmbiguousDst ? KindLocalAmbiguousDst : KindLocal));
178         }
179 
180         // Constructs a DateTime from a given year, month, and day. The
181         // time-of-day of the resulting DateTime is always midnight.
182         //
DateTimeSystem.DateTime183         public DateTime(int year, int month, int day)
184         {
185             _dateData = (UInt64)DateToTicks(year, month, day);
186         }
187 
188         // Constructs a DateTime from a given year, month, and day for
189         // the specified calendar. The
190         // time-of-day of the resulting DateTime is always midnight.
191         //
DateTimeSystem.DateTime192         public DateTime(int year, int month, int day, Calendar calendar)
193             : this(year, month, day, 0, 0, 0, calendar)
194         {
195         }
196 
197         // Constructs a DateTime from a given year, month, day, hour,
198         // minute, and second.
199         //
DateTimeSystem.DateTime200         public DateTime(int year, int month, int day, int hour, int minute, int second)
201         {
202             _dateData = (UInt64)(DateToTicks(year, month, day) + TimeToTicks(hour, minute, second));
203         }
204 
DateTimeSystem.DateTime205         public DateTime(int year, int month, int day, int hour, int minute, int second, DateTimeKind kind)
206         {
207             if (kind < DateTimeKind.Unspecified || kind > DateTimeKind.Local)
208             {
209                 throw new ArgumentException(SR.Argument_InvalidDateTimeKind, nameof(kind));
210             }
211             Int64 ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
212             _dateData = ((UInt64)ticks | ((UInt64)kind << KindShift));
213         }
214 
215         // Constructs a DateTime from a given year, month, day, hour,
216         // minute, and second for the specified calendar.
217         //
DateTimeSystem.DateTime218         public DateTime(int year, int month, int day, int hour, int minute, int second, Calendar calendar)
219         {
220             if (calendar == null)
221                 throw new ArgumentNullException(nameof(calendar));
222             _dateData = (UInt64)calendar.ToDateTime(year, month, day, hour, minute, second, 0).Ticks;
223         }
224 
225         // Constructs a DateTime from a given year, month, day, hour,
226         // minute, and second.
227         //
DateTimeSystem.DateTime228         public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond)
229         {
230             if (millisecond < 0 || millisecond >= MillisPerSecond)
231             {
232                 throw new ArgumentOutOfRangeException(nameof(millisecond), SR.Format(SR.ArgumentOutOfRange_Range, 0, MillisPerSecond - 1));
233             }
234             Int64 ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
235             ticks += millisecond * TicksPerMillisecond;
236             if (ticks < MinTicks || ticks > MaxTicks)
237                 throw new ArgumentException(SR.Arg_DateTimeRange);
238             _dateData = (UInt64)ticks;
239         }
240 
DateTimeSystem.DateTime241         public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind)
242         {
243             if (millisecond < 0 || millisecond >= MillisPerSecond)
244             {
245                 throw new ArgumentOutOfRangeException(nameof(millisecond), SR.Format(SR.ArgumentOutOfRange_Range, 0, MillisPerSecond - 1));
246             }
247             if (kind < DateTimeKind.Unspecified || kind > DateTimeKind.Local)
248             {
249                 throw new ArgumentException(SR.Argument_InvalidDateTimeKind, nameof(kind));
250             }
251             Int64 ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
252             ticks += millisecond * TicksPerMillisecond;
253             if (ticks < MinTicks || ticks > MaxTicks)
254                 throw new ArgumentException(SR.Arg_DateTimeRange);
255             _dateData = ((UInt64)ticks | ((UInt64)kind << KindShift));
256         }
257 
258         // Constructs a DateTime from a given year, month, day, hour,
259         // minute, and second for the specified calendar.
260         //
DateTimeSystem.DateTime261         public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar)
262         {
263             if (calendar == null)
264                 throw new ArgumentNullException(nameof(calendar));
265             if (millisecond < 0 || millisecond >= MillisPerSecond)
266             {
267                 throw new ArgumentOutOfRangeException(nameof(millisecond), SR.Format(SR.ArgumentOutOfRange_Range, 0, MillisPerSecond - 1));
268             }
269             Int64 ticks = calendar.ToDateTime(year, month, day, hour, minute, second, 0).Ticks;
270             ticks += millisecond * TicksPerMillisecond;
271             if (ticks < MinTicks || ticks > MaxTicks)
272                 throw new ArgumentException(SR.Arg_DateTimeRange);
273             _dateData = (UInt64)ticks;
274         }
275 
DateTimeSystem.DateTime276         public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, DateTimeKind kind)
277         {
278             if (calendar == null)
279                 throw new ArgumentNullException(nameof(calendar));
280             if (millisecond < 0 || millisecond >= MillisPerSecond)
281             {
282                 throw new ArgumentOutOfRangeException(nameof(millisecond), SR.Format(SR.ArgumentOutOfRange_Range, 0, MillisPerSecond - 1));
283             }
284             if (kind < DateTimeKind.Unspecified || kind > DateTimeKind.Local)
285             {
286                 throw new ArgumentException(SR.Argument_InvalidDateTimeKind, nameof(kind));
287             }
288             Int64 ticks = calendar.ToDateTime(year, month, day, hour, minute, second, 0).Ticks;
289             ticks += millisecond * TicksPerMillisecond;
290             if (ticks < MinTicks || ticks > MaxTicks)
291                 throw new ArgumentException(SR.Arg_DateTimeRange);
292             _dateData = ((UInt64)ticks | ((UInt64)kind << KindShift));
293         }
294 
DateTimeSystem.DateTime295         private DateTime(SerializationInfo info, StreamingContext context)
296         {
297             if (info == null)
298                 throw new ArgumentNullException(nameof(info));
299 
300             Boolean foundTicks = false;
301             Boolean foundDateData = false;
302             Int64 serializedTicks = 0;
303             UInt64 serializedDateData = 0;
304 
305 
306             // Get the data
307             SerializationInfoEnumerator enumerator = info.GetEnumerator();
308             while (enumerator.MoveNext())
309             {
310                 switch (enumerator.Name)
311                 {
312                     case TicksField:
313                         serializedTicks = Convert.ToInt64(enumerator.Value, CultureInfo.InvariantCulture);
314                         foundTicks = true;
315                         break;
316                     case DateDataField:
317                         serializedDateData = Convert.ToUInt64(enumerator.Value, CultureInfo.InvariantCulture);
318                         foundDateData = true;
319                         break;
320                     default:
321                         // Ignore other fields for forward compatibility.
322                         break;
323                 }
324             }
325             if (foundDateData)
326             {
327                 _dateData = serializedDateData;
328             }
329             else if (foundTicks)
330             {
331                 _dateData = (UInt64)serializedTicks;
332             }
333             else
334             {
335                 throw new SerializationException(SR.Serialization_MissingDateTimeData);
336             }
337             Int64 ticks = InternalTicks;
338             if (ticks < MinTicks || ticks > MaxTicks)
339             {
340                 throw new SerializationException(SR.Serialization_DateTimeTicksOutOfRange);
341             }
342         }
343 
344 
345 
346         internal Int64 InternalTicks
347         {
348             get
349             {
350                 return (Int64)(_dateData & TicksMask);
351             }
352         }
353 
354         private UInt64 InternalKind
355         {
356             get
357             {
358                 return (_dateData & FlagsMask);
359             }
360         }
361 
362         // Returns the DateTime resulting from adding the given
363         // TimeSpan to this DateTime.
364         //
AddSystem.DateTime365         public DateTime Add(TimeSpan value)
366         {
367             return AddTicks(value._ticks);
368         }
369 
370         // Returns the DateTime resulting from adding a fractional number of
371         // time units to this DateTime.
AddSystem.DateTime372         private DateTime Add(double value, int scale)
373         {
374             long millis = (long)(value * scale + (value >= 0 ? 0.5 : -0.5));
375             if (millis <= -MaxMillis || millis >= MaxMillis)
376                 throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_AddValue);
377             return AddTicks(millis * TicksPerMillisecond);
378         }
379 
380         // Returns the DateTime resulting from adding a fractional number of
381         // days to this DateTime. The result is computed by rounding the
382         // fractional number of days given by value to the nearest
383         // millisecond, and adding that interval to this DateTime. The
384         // value argument is permitted to be negative.
385         //
AddDaysSystem.DateTime386         public DateTime AddDays(double value)
387         {
388             return Add(value, MillisPerDay);
389         }
390 
391         // Returns the DateTime resulting from adding a fractional number of
392         // hours to this DateTime. The result is computed by rounding the
393         // fractional number of hours given by value to the nearest
394         // millisecond, and adding that interval to this DateTime. The
395         // value argument is permitted to be negative.
396         //
AddHoursSystem.DateTime397         public DateTime AddHours(double value)
398         {
399             return Add(value, MillisPerHour);
400         }
401 
402         // Returns the DateTime resulting from the given number of
403         // milliseconds to this DateTime. The result is computed by rounding
404         // the number of milliseconds given by value to the nearest integer,
405         // and adding that interval to this DateTime. The value
406         // argument is permitted to be negative.
407         //
AddMillisecondsSystem.DateTime408         public DateTime AddMilliseconds(double value)
409         {
410             return Add(value, 1);
411         }
412 
413         // Returns the DateTime resulting from adding a fractional number of
414         // minutes to this DateTime. The result is computed by rounding the
415         // fractional number of minutes given by value to the nearest
416         // millisecond, and adding that interval to this DateTime. The
417         // value argument is permitted to be negative.
418         //
AddMinutesSystem.DateTime419         public DateTime AddMinutes(double value)
420         {
421             return Add(value, MillisPerMinute);
422         }
423 
424         // Returns the DateTime resulting from adding the given number of
425         // months to this DateTime. The result is computed by incrementing
426         // (or decrementing) the year and month parts of this DateTime by
427         // months months, and, if required, adjusting the day part of the
428         // resulting date downwards to the last day of the resulting month in the
429         // resulting year. The time-of-day part of the result is the same as the
430         // time-of-day part of this DateTime.
431         //
432         // In more precise terms, considering this DateTime to be of the
433         // form y / m / d + t, where y is the
434         // year, m is the month, d is the day, and t is the
435         // time-of-day, the result is y1 / m1 / d1 + t,
436         // where y1 and m1 are computed by adding months months
437         // to y and m, and d1 is the largest value less than
438         // or equal to d that denotes a valid day in month m1 of year
439         // y1.
440         //
AddMonthsSystem.DateTime441         public DateTime AddMonths(int months)
442         {
443             if (months < -120000 || months > 120000) throw new ArgumentOutOfRangeException(nameof(months), SR.ArgumentOutOfRange_DateTimeBadMonths);
444             GetDatePart(out int y, out int m, out int d);
445             int i = m - 1 + months;
446             if (i >= 0)
447             {
448                 m = i % 12 + 1;
449                 y = y + i / 12;
450             }
451             else
452             {
453                 m = 12 + (i + 1) % 12;
454                 y = y + (i - 11) / 12;
455             }
456             if (y < 1 || y > 9999)
457             {
458                 throw new ArgumentOutOfRangeException(nameof(months), SR.ArgumentOutOfRange_DateArithmetic);
459             }
460             int days = DaysInMonth(y, m);
461             if (d > days) d = days;
462             return new DateTime((UInt64)(DateToTicks(y, m, d) + InternalTicks % TicksPerDay) | InternalKind);
463         }
464 
465         // Returns the DateTime resulting from adding a fractional number of
466         // seconds to this DateTime. The result is computed by rounding the
467         // fractional number of seconds given by value to the nearest
468         // millisecond, and adding that interval to this DateTime. The
469         // value argument is permitted to be negative.
470         //
AddSecondsSystem.DateTime471         public DateTime AddSeconds(double value)
472         {
473             return Add(value, MillisPerSecond);
474         }
475 
476         // Returns the DateTime resulting from adding the given number of
477         // 100-nanosecond ticks to this DateTime. The value argument
478         // is permitted to be negative.
479         //
AddTicksSystem.DateTime480         public DateTime AddTicks(long value)
481         {
482             long ticks = InternalTicks;
483             if (value > MaxTicks - ticks || value < MinTicks - ticks)
484             {
485                 throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_DateArithmetic);
486             }
487             return new DateTime((UInt64)(ticks + value) | InternalKind);
488         }
489 
490         // Returns the DateTime resulting from adding the given number of
491         // years to this DateTime. The result is computed by incrementing
492         // (or decrementing) the year part of this DateTime by value
493         // years. If the month and day of this DateTime is 2/29, and if the
494         // resulting year is not a leap year, the month and day of the resulting
495         // DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
496         // parts of the result are the same as those of this DateTime.
497         //
AddYearsSystem.DateTime498         public DateTime AddYears(int value)
499         {
500             if (value < -10000 || value > 10000)
501             {
502                 // DateTimeOffset.AddYears(int years) is implemented on top of DateTime.AddYears(int value). Use the more appropriate
503                 // parameter name out of the two for the exception.
504                 throw new ArgumentOutOfRangeException("years", SR.ArgumentOutOfRange_DateTimeBadYears);
505             }
506             return AddMonths(value * 12);
507         }
508 
509         // Compares two DateTime values, returning an integer that indicates
510         // their relationship.
511         //
CompareSystem.DateTime512         public static int Compare(DateTime t1, DateTime t2)
513         {
514             Int64 ticks1 = t1.InternalTicks;
515             Int64 ticks2 = t2.InternalTicks;
516             if (ticks1 > ticks2) return 1;
517             if (ticks1 < ticks2) return -1;
518             return 0;
519         }
520 
521         // Compares this DateTime to a given object. This method provides an
522         // implementation of the IComparable interface. The object
523         // argument must be another DateTime, or otherwise an exception
524         // occurs.  Null is considered less than any instance.
525         //
526         // Returns a value less than zero if this  object
CompareToSystem.DateTime527         public int CompareTo(Object value)
528         {
529             if (value == null) return 1;
530             if (!(value is DateTime))
531             {
532                 throw new ArgumentException(SR.Arg_MustBeDateTime);
533             }
534 
535             return Compare(this, (DateTime)value);
536         }
537 
CompareToSystem.DateTime538         public int CompareTo(DateTime value)
539         {
540             return Compare(this, value);
541         }
542 
543         // Returns the tick count corresponding to the given year, month, and day.
544         // Will check the if the parameters are valid.
DateToTicksSystem.DateTime545         private static long DateToTicks(int year, int month, int day)
546         {
547             if (year >= 1 && year <= 9999 && month >= 1 && month <= 12)
548             {
549                 int[] days = IsLeapYear(year) ? s_daysToMonth366 : s_daysToMonth365;
550                 if (day >= 1 && day <= days[month] - days[month - 1])
551                 {
552                     int y = year - 1;
553                     int n = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1;
554                     return n * TicksPerDay;
555                 }
556             }
557             throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay);
558         }
559 
560         // Return the tick count corresponding to the given hour, minute, second.
561         // Will check the if the parameters are valid.
TimeToTicksSystem.DateTime562         private static long TimeToTicks(int hour, int minute, int second)
563         {
564             //TimeSpan.TimeToTicks is a family access function which does no error checking, so
565             //we need to put some error checking out here.
566             if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >= 0 && second < 60)
567             {
568                 return (TimeSpan.TimeToTicks(hour, minute, second));
569             }
570             throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
571         }
572 
573         // Returns the number of days in the month given by the year and
574         // month arguments.
575         //
DaysInMonthSystem.DateTime576         public static int DaysInMonth(int year, int month)
577         {
578             if (month < 1 || month > 12) throw new ArgumentOutOfRangeException(nameof(month), SR.ArgumentOutOfRange_Month);
579             // IsLeapYear checks the year argument
580             int[] days = IsLeapYear(year) ? s_daysToMonth366 : s_daysToMonth365;
581             return days[month] - days[month - 1];
582         }
583 
584         // Converts an OLE Date to a tick count.
585         // This function is duplicated in COMDateTime.cpp
DoubleDateToTicksSystem.DateTime586         internal static long DoubleDateToTicks(double value)
587         {
588             // The check done this way will take care of NaN
589             if (!(value < OADateMaxAsDouble) || !(value > OADateMinAsDouble))
590                 throw new ArgumentException(SR.Arg_OleAutDateInvalid);
591 
592             // Conversion to long will not cause an overflow here, as at this point the "value" is in between OADateMinAsDouble and OADateMaxAsDouble
593             long millis = (long)(value * MillisPerDay + (value >= 0 ? 0.5 : -0.5));
594             // The interesting thing here is when you have a value like 12.5 it all positive 12 days and 12 hours from 01/01/1899
595             // However if you a value of -12.25 it is minus 12 days but still positive 6 hours, almost as though you meant -11.75 all negative
596             // This line below fixes up the millis in the negative case
597             if (millis < 0)
598             {
599                 millis -= (millis % MillisPerDay) * 2;
600             }
601 
602             millis += DoubleDateOffset / TicksPerMillisecond;
603 
604             if (millis < 0 || millis >= MaxMillis) throw new ArgumentException(SR.Arg_OleAutDateScale);
605             return millis * TicksPerMillisecond;
606         }
607 
608         // Checks if this DateTime is equal to a given object. Returns
609         // true if the given object is a boxed DateTime and its value
610         // is equal to the value of this DateTime. Returns false
611         // otherwise.
612         //
EqualsSystem.DateTime613         public override bool Equals(Object value)
614         {
615             if (value is DateTime)
616             {
617                 return InternalTicks == ((DateTime)value).InternalTicks;
618             }
619             return false;
620         }
621 
EqualsSystem.DateTime622         public bool Equals(DateTime value)
623         {
624             return InternalTicks == value.InternalTicks;
625         }
626 
627         // Compares two DateTime values for equality. Returns true if
628         // the two DateTime values are equal, or false if they are
629         // not equal.
630         //
EqualsSystem.DateTime631         public static bool Equals(DateTime t1, DateTime t2)
632         {
633             return t1.InternalTicks == t2.InternalTicks;
634         }
635 
FromBinarySystem.DateTime636         public static DateTime FromBinary(Int64 dateData)
637         {
638             if ((dateData & (unchecked((Int64)LocalMask))) != 0)
639             {
640                 // Local times need to be adjusted as you move from one time zone to another,
641                 // just as they are when serializing in text. As such the format for local times
642                 // changes to store the ticks of the UTC time, but with flags that look like a
643                 // local date.
644                 Int64 ticks = dateData & (unchecked((Int64)TicksMask));
645                 // Negative ticks are stored in the top part of the range and should be converted back into a negative number
646                 if (ticks > TicksCeiling - TicksPerDay)
647                 {
648                     ticks = ticks - TicksCeiling;
649                 }
650                 // Convert the ticks back to local. If the UTC ticks are out of range, we need to default to
651                 // the UTC offset from MinValue and MaxValue to be consistent with Parse.
652                 Boolean isAmbiguousLocalDst = false;
653                 Int64 offsetTicks;
654                 if (ticks < MinTicks)
655                 {
656                     offsetTicks = TimeZoneInfo.GetLocalUtcOffset(DateTime.MinValue, TimeZoneInfoOptions.NoThrowOnInvalidTime).Ticks;
657                 }
658                 else if (ticks > MaxTicks)
659                 {
660                     offsetTicks = TimeZoneInfo.GetLocalUtcOffset(DateTime.MaxValue, TimeZoneInfoOptions.NoThrowOnInvalidTime).Ticks;
661                 }
662                 else
663                 {
664                     // Because the ticks conversion between UTC and local is lossy, we need to capture whether the
665                     // time is in a repeated hour so that it can be passed to the DateTime constructor.
666                     DateTime utcDt = new DateTime(ticks, DateTimeKind.Utc);
667                     Boolean isDaylightSavings = false;
668                     offsetTicks = TimeZoneInfo.GetUtcOffsetFromUtc(utcDt, TimeZoneInfo.Local, out isDaylightSavings, out isAmbiguousLocalDst).Ticks;
669                 }
670                 ticks += offsetTicks;
671                 // Another behaviour of parsing is to cause small times to wrap around, so that they can be used
672                 // to compare times of day
673                 if (ticks < 0)
674                 {
675                     ticks += TicksPerDay;
676                 }
677                 if (ticks < MinTicks || ticks > MaxTicks)
678                 {
679                     throw new ArgumentException(SR.Argument_DateTimeBadBinaryData, nameof(dateData));
680                 }
681                 return new DateTime(ticks, DateTimeKind.Local, isAmbiguousLocalDst);
682             }
683             else
684             {
685                 return DateTime.FromBinaryRaw(dateData);
686             }
687         }
688 
689         // A version of ToBinary that uses the real representation and does not adjust local times. This is needed for
690         // scenarios where the serialized data must maintain compatibility
FromBinaryRawSystem.DateTime691         internal static DateTime FromBinaryRaw(Int64 dateData)
692         {
693             Int64 ticks = dateData & (Int64)TicksMask;
694             if (ticks < MinTicks || ticks > MaxTicks)
695                 throw new ArgumentException(SR.Argument_DateTimeBadBinaryData, nameof(dateData));
696             return new DateTime((UInt64)dateData);
697         }
698 
699         // Creates a DateTime from a Windows filetime. A Windows filetime is
700         // a long representing the date and time as the number of
701         // 100-nanosecond intervals that have elapsed since 1/1/1601 12:00am.
702         //
FromFileTimeSystem.DateTime703         public static DateTime FromFileTime(long fileTime)
704         {
705             return FromFileTimeUtc(fileTime).ToLocalTime();
706         }
707 
FromFileTimeUtcSystem.DateTime708         public static DateTime FromFileTimeUtc(long fileTime)
709         {
710             if (fileTime < 0 || fileTime > MaxTicks - FileTimeOffset)
711             {
712                 throw new ArgumentOutOfRangeException(nameof(fileTime), SR.ArgumentOutOfRange_FileTimeInvalid);
713             }
714 
715             // This is the ticks in Universal time for this fileTime.
716             long universalTicks = fileTime + FileTimeOffset;
717             return new DateTime(universalTicks, DateTimeKind.Utc);
718         }
719 
720         // Creates a DateTime from an OLE Automation Date.
721         //
FromOADateSystem.DateTime722         public static DateTime FromOADate(double d)
723         {
724             return new DateTime(DoubleDateToTicks(d), DateTimeKind.Unspecified);
725         }
726 
ISerializable.GetObjectDataSystem.DateTime727         void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
728         {
729             if (info == null)
730             {
731                 throw new ArgumentNullException(nameof(info));
732             }
733 
734             // Serialize both the old and the new format
735             info.AddValue(TicksField, InternalTicks);
736             info.AddValue(DateDataField, _dateData);
737         }
738 
IsDaylightSavingTimeSystem.DateTime739         public Boolean IsDaylightSavingTime()
740         {
741             if (Kind == DateTimeKind.Utc)
742             {
743                 return false;
744             }
745             return TimeZoneInfo.Local.IsDaylightSavingTime(this, TimeZoneInfoOptions.NoThrowOnInvalidTime);
746         }
747 
SpecifyKindSystem.DateTime748         public static DateTime SpecifyKind(DateTime value, DateTimeKind kind)
749         {
750             return new DateTime(value.InternalTicks, kind);
751         }
752 
ToBinarySystem.DateTime753         public Int64 ToBinary()
754         {
755             if (Kind == DateTimeKind.Local)
756             {
757                 // Local times need to be adjusted as you move from one time zone to another,
758                 // just as they are when serializing in text. As such the format for local times
759                 // changes to store the ticks of the UTC time, but with flags that look like a
760                 // local date.
761 
762                 // To match serialization in text we need to be able to handle cases where
763                 // the UTC value would be out of range. Unused parts of the ticks range are
764                 // used for this, so that values just past max value are stored just past the
765                 // end of the maximum range, and values just below minimum value are stored
766                 // at the end of the ticks area, just below 2^62.
767                 TimeSpan offset = TimeZoneInfo.GetLocalUtcOffset(this, TimeZoneInfoOptions.NoThrowOnInvalidTime);
768                 Int64 ticks = Ticks;
769                 Int64 storedTicks = ticks - offset.Ticks;
770                 if (storedTicks < 0)
771                 {
772                     storedTicks = TicksCeiling + storedTicks;
773                 }
774                 return storedTicks | (unchecked((Int64)LocalMask));
775             }
776             else
777             {
778                 return (Int64)_dateData;
779             }
780         }
781 
782         // Returns the date part of this DateTime. The resulting value
783         // corresponds to this DateTime with the time-of-day part set to
784         // zero (midnight).
785         //
786         public DateTime Date
787         {
788             get
789             {
790                 Int64 ticks = InternalTicks;
791                 return new DateTime((UInt64)(ticks - ticks % TicksPerDay) | InternalKind);
792             }
793         }
794 
795         // Returns a given date part of this DateTime. This method is used
796         // to compute the year, day-of-year, month, or day part.
GetDatePartSystem.DateTime797         private int GetDatePart(int part)
798         {
799             Int64 ticks = InternalTicks;
800             // n = number of days since 1/1/0001
801             int n = (int)(ticks / TicksPerDay);
802             // y400 = number of whole 400-year periods since 1/1/0001
803             int y400 = n / DaysPer400Years;
804             // n = day number within 400-year period
805             n -= y400 * DaysPer400Years;
806             // y100 = number of whole 100-year periods within 400-year period
807             int y100 = n / DaysPer100Years;
808             // Last 100-year period has an extra day, so decrement result if 4
809             if (y100 == 4) y100 = 3;
810             // n = day number within 100-year period
811             n -= y100 * DaysPer100Years;
812             // y4 = number of whole 4-year periods within 100-year period
813             int y4 = n / DaysPer4Years;
814             // n = day number within 4-year period
815             n -= y4 * DaysPer4Years;
816             // y1 = number of whole years within 4-year period
817             int y1 = n / DaysPerYear;
818             // Last year has an extra day, so decrement result if 4
819             if (y1 == 4) y1 = 3;
820             // If year was requested, compute and return it
821             if (part == DatePartYear)
822             {
823                 return y400 * 400 + y100 * 100 + y4 * 4 + y1 + 1;
824             }
825             // n = day number within year
826             n -= y1 * DaysPerYear;
827             // If day-of-year was requested, return it
828             if (part == DatePartDayOfYear) return n + 1;
829             // Leap year calculation looks different from IsLeapYear since y1, y4,
830             // and y100 are relative to year 1, not year 0
831             bool leapYear = y1 == 3 && (y4 != 24 || y100 == 3);
832             int[] days = leapYear ? s_daysToMonth366 : s_daysToMonth365;
833             // All months have less than 32 days, so n >> 5 is a good conservative
834             // estimate for the month
835             int m = (n >> 5) + 1;
836             // m = 1-based month number
837             while (n >= days[m]) m++;
838             // If month was requested, return it
839             if (part == DatePartMonth) return m;
840             // Return 1-based day-of-month
841             return n - days[m - 1] + 1;
842         }
843 
844         // Exactly the same as GetDatePart(int part), except computing all of
845         // year/month/day rather than just one of them.  Used when all three
846         // are needed rather than redoing the computations for each.
GetDatePartSystem.DateTime847         internal void GetDatePart(out int year, out int month, out int day)
848         {
849             Int64 ticks = InternalTicks;
850             // n = number of days since 1/1/0001
851             int n = (int)(ticks / TicksPerDay);
852             // y400 = number of whole 400-year periods since 1/1/0001
853             int y400 = n / DaysPer400Years;
854             // n = day number within 400-year period
855             n -= y400 * DaysPer400Years;
856             // y100 = number of whole 100-year periods within 400-year period
857             int y100 = n / DaysPer100Years;
858             // Last 100-year period has an extra day, so decrement result if 4
859             if (y100 == 4) y100 = 3;
860             // n = day number within 100-year period
861             n -= y100 * DaysPer100Years;
862             // y4 = number of whole 4-year periods within 100-year period
863             int y4 = n / DaysPer4Years;
864             // n = day number within 4-year period
865             n -= y4 * DaysPer4Years;
866             // y1 = number of whole years within 4-year period
867             int y1 = n / DaysPerYear;
868             // Last year has an extra day, so decrement result if 4
869             if (y1 == 4) y1 = 3;
870             // compute year
871             year = y400 * 400 + y100 * 100 + y4 * 4 + y1 + 1;
872             // n = day number within year
873             n -= y1 * DaysPerYear;
874             // dayOfYear = n + 1;
875             // Leap year calculation looks different from IsLeapYear since y1, y4,
876             // and y100 are relative to year 1, not year 0
877             bool leapYear = y1 == 3 && (y4 != 24 || y100 == 3);
878             int[] days = leapYear ? s_daysToMonth366 : s_daysToMonth365;
879             // All months have less than 32 days, so n >> 5 is a good conservative
880             // estimate for the month
881             int m = (n >> 5) + 1;
882             // m = 1-based month number
883             while (n >= days[m]) m++;
884             // compute month and day
885             month = m;
886             day = n - days[m - 1] + 1;
887         }
888 
889         // Returns the day-of-month part of this DateTime. The returned
890         // value is an integer between 1 and 31.
891         //
892         public int Day
893         {
894             get
895             {
896                 return GetDatePart(DatePartDay);
897             }
898         }
899 
900         // Returns the day-of-week part of this DateTime. The returned value
901         // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
902         // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
903         // Thursday, 5 indicates Friday, and 6 indicates Saturday.
904         //
905         public DayOfWeek DayOfWeek
906         {
907             get
908             {
909                 return (DayOfWeek)((InternalTicks / TicksPerDay + 1) % 7);
910             }
911         }
912 
913         // Returns the day-of-year part of this DateTime. The returned value
914         // is an integer between 1 and 366.
915         //
916         public int DayOfYear
917         {
918             get
919             {
920                 return GetDatePart(DatePartDayOfYear);
921             }
922         }
923 
924         // Returns the hash code for this DateTime.
925         //
GetHashCodeSystem.DateTime926         public override int GetHashCode()
927         {
928             Int64 ticks = InternalTicks;
929             return unchecked((int)ticks) ^ (int)(ticks >> 32);
930         }
931 
932         // Returns the hour part of this DateTime. The returned value is an
933         // integer between 0 and 23.
934         //
935         public int Hour
936         {
937             get
938             {
939                 return (int)((InternalTicks / TicksPerHour) % 24);
940             }
941         }
942 
IsAmbiguousDaylightSavingTimeSystem.DateTime943         internal Boolean IsAmbiguousDaylightSavingTime()
944         {
945             return (InternalKind == KindLocalAmbiguousDst);
946         }
947 
948         public DateTimeKind Kind
949         {
950             get
951             {
952                 switch (InternalKind)
953                 {
954                     case KindUnspecified:
955                         return DateTimeKind.Unspecified;
956                     case KindUtc:
957                         return DateTimeKind.Utc;
958                     default:
959                         return DateTimeKind.Local;
960                 }
961             }
962         }
963 
964         // Returns the millisecond part of this DateTime. The returned value
965         // is an integer between 0 and 999.
966         //
967         public int Millisecond
968         {
969             get
970             {
971                 return (int)((InternalTicks / TicksPerMillisecond) % 1000);
972             }
973         }
974 
975         // Returns the minute part of this DateTime. The returned value is
976         // an integer between 0 and 59.
977         //
978         public int Minute
979         {
980             get
981             {
982                 return (int)((InternalTicks / TicksPerMinute) % 60);
983             }
984         }
985 
986         // Returns the month part of this DateTime. The returned value is an
987         // integer between 1 and 12.
988         //
989         public int Month
990         {
991             get
992             {
993                 return GetDatePart(DatePartMonth);
994             }
995         }
996 
997         // Returns a DateTime representing the current date and time. The
998         // resolution of the returned value depends on the system timer.
999         public static DateTime Now
1000         {
1001             get
1002             {
1003                 DateTime utc = UtcNow;
1004                 Boolean isAmbiguousLocalDst = false;
1005                 Int64 offset = TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc(utc, out isAmbiguousLocalDst).Ticks;
1006                 long tick = utc.Ticks + offset;
1007                 if (tick > DateTime.MaxTicks)
1008                 {
1009                     return new DateTime(DateTime.MaxTicks, DateTimeKind.Local);
1010                 }
1011                 if (tick < DateTime.MinTicks)
1012                 {
1013                     return new DateTime(DateTime.MinTicks, DateTimeKind.Local);
1014                 }
1015                 return new DateTime(tick, DateTimeKind.Local, isAmbiguousLocalDst);
1016             }
1017         }
1018 
1019         // Returns the second part of this DateTime. The returned value is
1020         // an integer between 0 and 59.
1021         //
1022         public int Second
1023         {
1024             get
1025             {
1026                 return (int)((InternalTicks / TicksPerSecond) % 60);
1027             }
1028         }
1029 
1030         // Returns the tick count for this DateTime. The returned value is
1031         // the number of 100-nanosecond intervals that have elapsed since 1/1/0001
1032         // 12:00am.
1033         //
1034         public long Ticks
1035         {
1036             get
1037             {
1038                 return InternalTicks;
1039             }
1040         }
1041 
1042         // Returns the time-of-day part of this DateTime. The returned value
1043         // is a TimeSpan that indicates the time elapsed since midnight.
1044         //
1045         public TimeSpan TimeOfDay
1046         {
1047             get
1048             {
1049                 return new TimeSpan(InternalTicks % TicksPerDay);
1050             }
1051         }
1052 
1053         // Returns a DateTime representing the current date. The date part
1054         // of the returned value is the current date, and the time-of-day part of
1055         // the returned value is zero (midnight).
1056         //
1057         public static DateTime Today
1058         {
1059             get
1060             {
1061                 return DateTime.Now.Date;
1062             }
1063         }
1064 
1065         // Returns the year part of this DateTime. The returned value is an
1066         // integer between 1 and 9999.
1067         //
1068         public int Year
1069         {
1070             get
1071             {
1072                 return GetDatePart(DatePartYear);
1073             }
1074         }
1075 
1076         // Checks whether a given year is a leap year. This method returns true if
1077         // year is a leap year, or false if not.
1078         //
IsLeapYearSystem.DateTime1079         public static bool IsLeapYear(int year)
1080         {
1081             if (year < 1 || year > 9999)
1082             {
1083                 throw new ArgumentOutOfRangeException(nameof(year), SR.ArgumentOutOfRange_Year);
1084             }
1085             return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
1086         }
1087 
1088         // Constructs a DateTime from a string. The string must specify a
1089         // date and optionally a time in a culture-specific or universal format.
1090         // Leading and trailing whitespace characters are allowed.
1091         //
ParseSystem.DateTime1092         public static DateTime Parse(String s)
1093         {
1094             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
1095             return (DateTimeParse.Parse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None));
1096         }
1097 
1098         // Constructs a DateTime from a string. The string must specify a
1099         // date and optionally a time in a culture-specific or universal format.
1100         // Leading and trailing whitespace characters are allowed.
1101         //
ParseSystem.DateTime1102         public static DateTime Parse(String s, IFormatProvider provider)
1103         {
1104             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
1105             return (DateTimeParse.Parse(s, DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None));
1106         }
1107 
ParseSystem.DateTime1108         public static DateTime Parse(String s, IFormatProvider provider, DateTimeStyles styles)
1109         {
1110             DateTimeFormatInfo.ValidateStyles(styles, nameof(styles));
1111             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
1112             return (DateTimeParse.Parse(s, DateTimeFormatInfo.GetInstance(provider), styles));
1113         }
1114 
ParseSystem.DateTime1115         public static DateTime Parse(ReadOnlySpan<char> s, IFormatProvider provider = null, DateTimeStyles styles = DateTimeStyles.None)
1116         {
1117             DateTimeFormatInfo.ValidateStyles(styles, nameof(styles));
1118             return DateTimeParse.Parse(s, DateTimeFormatInfo.GetInstance(provider), styles);
1119         }
1120 
1121         // Constructs a DateTime from a string. The string must specify a
1122         // date and optionally a time in a culture-specific or universal format.
1123         // Leading and trailing whitespace characters are allowed.
1124         //
ParseExactSystem.DateTime1125         public static DateTime ParseExact(String s, String format, IFormatProvider provider)
1126         {
1127             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
1128             if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
1129             return (DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None));
1130         }
1131 
1132         // Constructs a DateTime from a string. The string must specify a
1133         // date and optionally a time in a culture-specific or universal format.
1134         // Leading and trailing whitespace characters are allowed.
1135         //
ParseExactSystem.DateTime1136         public static DateTime ParseExact(String s, String format, IFormatProvider provider, DateTimeStyles style)
1137         {
1138             DateTimeFormatInfo.ValidateStyles(style, nameof(style));
1139             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
1140             if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
1141             return (DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style));
1142         }
1143 
1144         // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
ParseExactSystem.DateTime1145         public static DateTime ParseExact(ReadOnlySpan<char> s, string format, IFormatProvider provider, DateTimeStyles style)
1146         {
1147             if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
1148             return ParseExact(s, (ReadOnlySpan<char>)format, provider, style);
1149         }
1150 
ParseExactSystem.DateTime1151         public static DateTime ParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, IFormatProvider provider, DateTimeStyles style = DateTimeStyles.None)
1152         {
1153             DateTimeFormatInfo.ValidateStyles(style, nameof(style));
1154             return DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style);
1155         }
1156 
ParseExactSystem.DateTime1157         public static DateTime ParseExact(String s, String[] formats, IFormatProvider provider, DateTimeStyles style)
1158         {
1159             DateTimeFormatInfo.ValidateStyles(style, nameof(style));
1160             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
1161             return DateTimeParse.ParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style);
1162         }
1163 
ParseExactSystem.DateTime1164         public static DateTime ParseExact(ReadOnlySpan<char> s, string[] formats, IFormatProvider provider, DateTimeStyles style = DateTimeStyles.None)
1165         {
1166             DateTimeFormatInfo.ValidateStyles(style, nameof(style));
1167             return DateTimeParse.ParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style);
1168         }
1169 
SubtractSystem.DateTime1170         public TimeSpan Subtract(DateTime value)
1171         {
1172             return new TimeSpan(InternalTicks - value.InternalTicks);
1173         }
1174 
SubtractSystem.DateTime1175         public DateTime Subtract(TimeSpan value)
1176         {
1177             long ticks = InternalTicks;
1178             long valueTicks = value._ticks;
1179             if (ticks - MinTicks < valueTicks || ticks - MaxTicks > valueTicks)
1180             {
1181                 throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_DateArithmetic);
1182             }
1183             return new DateTime((UInt64)(ticks - valueTicks) | InternalKind);
1184         }
1185 
1186         // This function is duplicated in COMDateTime.cpp
TicksToOADateSystem.DateTime1187         private static double TicksToOADate(long value)
1188         {
1189             if (value == 0)
1190                 return 0.0;  // Returns OleAut's zero'ed date value.
1191             if (value < TicksPerDay) // This is a fix for VB. They want the default day to be 1/1/0001 rathar then 12/30/1899.
1192                 value += DoubleDateOffset; // We could have moved this fix down but we would like to keep the bounds check.
1193             if (value < OADateMinAsTicks)
1194                 throw new OverflowException(SR.Arg_OleAutDateInvalid);
1195             // Currently, our max date == OA's max date (12/31/9999), so we don't
1196             // need an overflow check in that direction.
1197             long millis = (value - DoubleDateOffset) / TicksPerMillisecond;
1198             if (millis < 0)
1199             {
1200                 long frac = millis % MillisPerDay;
1201                 if (frac != 0) millis -= (MillisPerDay + frac) * 2;
1202             }
1203             return (double)millis / MillisPerDay;
1204         }
1205 
1206         // Converts the DateTime instance into an OLE Automation compatible
1207         // double date.
ToOADateSystem.DateTime1208         public double ToOADate()
1209         {
1210             return TicksToOADate(InternalTicks);
1211         }
1212 
ToFileTimeSystem.DateTime1213         public long ToFileTime()
1214         {
1215             // Treats the input as local if it is not specified
1216             return ToUniversalTime().ToFileTimeUtc();
1217         }
1218 
ToFileTimeUtcSystem.DateTime1219         public long ToFileTimeUtc()
1220         {
1221             // Treats the input as universal if it is not specified
1222             long ticks = ((InternalKind & LocalMask) != 0) ? ToUniversalTime().InternalTicks : this.InternalTicks;
1223             ticks -= FileTimeOffset;
1224             if (ticks < 0)
1225             {
1226                 throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_FileTimeInvalid);
1227             }
1228             return ticks;
1229         }
1230 
ToLocalTimeSystem.DateTime1231         public DateTime ToLocalTime()
1232         {
1233             return ToLocalTime(false);
1234         }
1235 
ToLocalTimeSystem.DateTime1236         internal DateTime ToLocalTime(bool throwOnOverflow)
1237         {
1238             if (Kind == DateTimeKind.Local)
1239             {
1240                 return this;
1241             }
1242             Boolean isDaylightSavings = false;
1243             Boolean isAmbiguousLocalDst = false;
1244             Int64 offset = TimeZoneInfo.GetUtcOffsetFromUtc(this, TimeZoneInfo.Local, out isDaylightSavings, out isAmbiguousLocalDst).Ticks;
1245             long tick = Ticks + offset;
1246             if (tick > DateTime.MaxTicks)
1247             {
1248                 if (throwOnOverflow)
1249                     throw new ArgumentException(SR.Arg_ArgumentOutOfRangeException);
1250                 else
1251                     return new DateTime(DateTime.MaxTicks, DateTimeKind.Local);
1252             }
1253             if (tick < DateTime.MinTicks)
1254             {
1255                 if (throwOnOverflow)
1256                     throw new ArgumentException(SR.Arg_ArgumentOutOfRangeException);
1257                 else
1258                     return new DateTime(DateTime.MinTicks, DateTimeKind.Local);
1259             }
1260             return new DateTime(tick, DateTimeKind.Local, isAmbiguousLocalDst);
1261         }
1262 
ToLongDateStringSystem.DateTime1263         public String ToLongDateString()
1264         {
1265             return DateTimeFormat.Format(this, "D", DateTimeFormatInfo.CurrentInfo);
1266         }
1267 
ToLongTimeStringSystem.DateTime1268         public String ToLongTimeString()
1269         {
1270             return DateTimeFormat.Format(this, "T", DateTimeFormatInfo.CurrentInfo);
1271         }
1272 
ToShortDateStringSystem.DateTime1273         public String ToShortDateString()
1274         {
1275             return DateTimeFormat.Format(this, "d", DateTimeFormatInfo.CurrentInfo);
1276         }
1277 
ToShortTimeStringSystem.DateTime1278         public String ToShortTimeString()
1279         {
1280             return DateTimeFormat.Format(this, "t", DateTimeFormatInfo.CurrentInfo);
1281         }
1282 
ToStringSystem.DateTime1283         public override String ToString()
1284         {
1285             return DateTimeFormat.Format(this, null, DateTimeFormatInfo.CurrentInfo);
1286         }
1287 
ToStringSystem.DateTime1288         public String ToString(String format)
1289         {
1290             return DateTimeFormat.Format(this, format, DateTimeFormatInfo.CurrentInfo);
1291         }
1292 
ToStringSystem.DateTime1293         public String ToString(IFormatProvider provider)
1294         {
1295             return DateTimeFormat.Format(this, null, DateTimeFormatInfo.GetInstance(provider));
1296         }
1297 
ToStringSystem.DateTime1298         public String ToString(String format, IFormatProvider provider)
1299         {
1300             return DateTimeFormat.Format(this, format, DateTimeFormatInfo.GetInstance(provider));
1301         }
1302 
1303         // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
TryFormatSystem.DateTime1304         public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
1305             TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
1306 
TryFormatSystem.DateTime1307         public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null) =>
1308             DateTimeFormat.TryFormat(this, destination, out charsWritten, format, DateTimeFormatInfo.GetInstance(provider));
1309 
ToUniversalTimeSystem.DateTime1310         public DateTime ToUniversalTime()
1311         {
1312             return TimeZoneInfo.ConvertTimeToUtc(this, TimeZoneInfoOptions.NoThrowOnInvalidTime);
1313         }
1314 
TryParseSystem.DateTime1315         public static Boolean TryParse(String s, out DateTime result)
1316         {
1317             if (s == null)
1318             {
1319                 result = default;
1320                 return false;
1321             }
1322             return DateTimeParse.TryParse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out result);
1323         }
1324 
TryParseSystem.DateTime1325         public static bool TryParse(ReadOnlySpan<char> s, out DateTime result)
1326         {
1327             return DateTimeParse.TryParse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out result);
1328         }
1329 
TryParseSystem.DateTime1330         public static Boolean TryParse(String s, IFormatProvider provider, DateTimeStyles styles, out DateTime result)
1331         {
1332             DateTimeFormatInfo.ValidateStyles(styles, nameof(styles));
1333 
1334             if (s == null)
1335             {
1336                 result = default;
1337                 return false;
1338             }
1339 
1340             return DateTimeParse.TryParse(s, DateTimeFormatInfo.GetInstance(provider), styles, out result);
1341         }
1342 
TryParseSystem.DateTime1343         public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, DateTimeStyles styles, out DateTime result)
1344         {
1345             DateTimeFormatInfo.ValidateStyles(styles, nameof(styles));
1346             return DateTimeParse.TryParse(s, DateTimeFormatInfo.GetInstance(provider), styles, out result);
1347         }
1348 
TryParseExactSystem.DateTime1349         public static Boolean TryParseExact(String s, String format, IFormatProvider provider, DateTimeStyles style, out DateTime result)
1350         {
1351             DateTimeFormatInfo.ValidateStyles(style, nameof(style));
1352 
1353             if (s == null || format == null)
1354             {
1355                 result = default;
1356                 return false;
1357             }
1358 
1359             return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result);
1360         }
1361 
1362         // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
TryParseExactSystem.DateTime1363         public static bool TryParseExact(ReadOnlySpan<char> s, string format, IFormatProvider provider, DateTimeStyles style, out DateTime result)
1364         {
1365             if (format == null)
1366             {
1367                 result = default;
1368                 return false;
1369             }
1370 
1371             return TryParseExact(s, (ReadOnlySpan<char>)format, provider, style, out result);
1372         }
1373 
TryParseExactSystem.DateTime1374         public static bool TryParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, IFormatProvider provider, DateTimeStyles style, out DateTime result)
1375         {
1376             DateTimeFormatInfo.ValidateStyles(style, nameof(style));
1377             return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result);
1378         }
1379 
TryParseExactSystem.DateTime1380         public static Boolean TryParseExact(String s, String[] formats, IFormatProvider provider, DateTimeStyles style, out DateTime result)
1381         {
1382             DateTimeFormatInfo.ValidateStyles(style, nameof(style));
1383 
1384             if (s == null)
1385             {
1386                 result = default;
1387                 return false;
1388             }
1389 
1390             return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result);
1391         }
1392 
TryParseExactSystem.DateTime1393         public static bool TryParseExact(ReadOnlySpan<char> s, string[] formats, IFormatProvider provider, DateTimeStyles style, out DateTime result)
1394         {
1395             DateTimeFormatInfo.ValidateStyles(style, nameof(style));
1396             return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result);
1397         }
1398 
operator +System.DateTime1399         public static DateTime operator +(DateTime d, TimeSpan t)
1400         {
1401             long ticks = d.InternalTicks;
1402             long valueTicks = t._ticks;
1403             if (valueTicks > MaxTicks - ticks || valueTicks < MinTicks - ticks)
1404             {
1405                 throw new ArgumentOutOfRangeException(nameof(t), SR.ArgumentOutOfRange_DateArithmetic);
1406             }
1407             return new DateTime((UInt64)(ticks + valueTicks) | d.InternalKind);
1408         }
1409 
operator -System.DateTime1410         public static DateTime operator -(DateTime d, TimeSpan t)
1411         {
1412             long ticks = d.InternalTicks;
1413             long valueTicks = t._ticks;
1414             if (ticks - MinTicks < valueTicks || ticks - MaxTicks > valueTicks)
1415             {
1416                 throw new ArgumentOutOfRangeException(nameof(t), SR.ArgumentOutOfRange_DateArithmetic);
1417             }
1418             return new DateTime((UInt64)(ticks - valueTicks) | d.InternalKind);
1419         }
1420 
operator -System.DateTime1421         public static TimeSpan operator -(DateTime d1, DateTime d2)
1422         {
1423             return new TimeSpan(d1.InternalTicks - d2.InternalTicks);
1424         }
1425 
operator ==System.DateTime1426         public static bool operator ==(DateTime d1, DateTime d2)
1427         {
1428             return d1.InternalTicks == d2.InternalTicks;
1429         }
1430 
operator !=System.DateTime1431         public static bool operator !=(DateTime d1, DateTime d2)
1432         {
1433             return d1.InternalTicks != d2.InternalTicks;
1434         }
1435 
operator <System.DateTime1436         public static bool operator <(DateTime t1, DateTime t2)
1437         {
1438             return t1.InternalTicks < t2.InternalTicks;
1439         }
1440 
operator <=System.DateTime1441         public static bool operator <=(DateTime t1, DateTime t2)
1442         {
1443             return t1.InternalTicks <= t2.InternalTicks;
1444         }
1445 
operator >System.DateTime1446         public static bool operator >(DateTime t1, DateTime t2)
1447         {
1448             return t1.InternalTicks > t2.InternalTicks;
1449         }
1450 
operator >=System.DateTime1451         public static bool operator >=(DateTime t1, DateTime t2)
1452         {
1453             return t1.InternalTicks >= t2.InternalTicks;
1454         }
1455 
1456 
1457         // Returns a string array containing all of the known date and time options for the
1458         // current culture.  The strings returned are properly formatted date and
1459         // time strings for the current instance of DateTime.
GetDateTimeFormatsSystem.DateTime1460         public String[] GetDateTimeFormats()
1461         {
1462             return (GetDateTimeFormats(CultureInfo.CurrentCulture));
1463         }
1464 
1465         // Returns a string array containing all of the known date and time options for the
1466         // using the information provided by IFormatProvider.  The strings returned are properly formatted date and
1467         // time strings for the current instance of DateTime.
GetDateTimeFormatsSystem.DateTime1468         public String[] GetDateTimeFormats(IFormatProvider provider)
1469         {
1470             return (DateTimeFormat.GetAllDateTimes(this, DateTimeFormatInfo.GetInstance(provider)));
1471         }
1472 
1473 
1474         // Returns a string array containing all of the date and time options for the
1475         // given format format and current culture.  The strings returned are properly formatted date and
1476         // time strings for the current instance of DateTime.
GetDateTimeFormatsSystem.DateTime1477         public String[] GetDateTimeFormats(char format)
1478         {
1479             return (GetDateTimeFormats(format, CultureInfo.CurrentCulture));
1480         }
1481 
1482         // Returns a string array containing all of the date and time options for the
1483         // given format format and given culture.  The strings returned are properly formatted date and
1484         // time strings for the current instance of DateTime.
GetDateTimeFormatsSystem.DateTime1485         public String[] GetDateTimeFormats(char format, IFormatProvider provider)
1486         {
1487             return (DateTimeFormat.GetAllDateTimes(this, format, DateTimeFormatInfo.GetInstance(provider)));
1488         }
1489 
1490         //
1491         // IConvertible implementation
1492         //
1493 
GetTypeCodeSystem.DateTime1494         public TypeCode GetTypeCode()
1495         {
1496             return TypeCode.DateTime;
1497         }
1498 
1499 
IConvertible.ToBooleanSystem.DateTime1500         bool IConvertible.ToBoolean(IFormatProvider provider)
1501         {
1502             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Boolean"));
1503         }
1504 
IConvertible.ToCharSystem.DateTime1505         char IConvertible.ToChar(IFormatProvider provider)
1506         {
1507             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Char"));
1508         }
1509 
IConvertible.ToSByteSystem.DateTime1510         sbyte IConvertible.ToSByte(IFormatProvider provider)
1511         {
1512             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "SByte"));
1513         }
1514 
IConvertible.ToByteSystem.DateTime1515         byte IConvertible.ToByte(IFormatProvider provider)
1516         {
1517             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Byte"));
1518         }
1519 
IConvertible.ToInt16System.DateTime1520         short IConvertible.ToInt16(IFormatProvider provider)
1521         {
1522             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Int16"));
1523         }
1524 
IConvertible.ToUInt16System.DateTime1525         ushort IConvertible.ToUInt16(IFormatProvider provider)
1526         {
1527             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "UInt16"));
1528         }
1529 
IConvertible.ToInt32System.DateTime1530         int IConvertible.ToInt32(IFormatProvider provider)
1531         {
1532             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Int32"));
1533         }
1534 
IConvertible.ToUInt32System.DateTime1535         uint IConvertible.ToUInt32(IFormatProvider provider)
1536         {
1537             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "UInt32"));
1538         }
1539 
IConvertible.ToInt64System.DateTime1540         long IConvertible.ToInt64(IFormatProvider provider)
1541         {
1542             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Int64"));
1543         }
1544 
IConvertible.ToUInt64System.DateTime1545         ulong IConvertible.ToUInt64(IFormatProvider provider)
1546         {
1547             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "UInt64"));
1548         }
1549 
IConvertible.ToSingleSystem.DateTime1550         float IConvertible.ToSingle(IFormatProvider provider)
1551         {
1552             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Single"));
1553         }
1554 
IConvertible.ToDoubleSystem.DateTime1555         double IConvertible.ToDouble(IFormatProvider provider)
1556         {
1557             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Double"));
1558         }
1559 
IConvertible.ToDecimalSystem.DateTime1560         Decimal IConvertible.ToDecimal(IFormatProvider provider)
1561         {
1562             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "DateTime", "Decimal"));
1563         }
1564 
IConvertible.ToDateTimeSystem.DateTime1565         DateTime IConvertible.ToDateTime(IFormatProvider provider)
1566         {
1567             return this;
1568         }
1569 
IConvertible.ToTypeSystem.DateTime1570         Object IConvertible.ToType(Type type, IFormatProvider provider)
1571         {
1572             return Convert.DefaultToType((IConvertible)this, type, provider);
1573         }
1574 
1575         // Tries to construct a DateTime from a given year, month, day, hour,
1576         // minute, second and millisecond.
1577         //
TryCreateSystem.DateTime1578         internal static Boolean TryCreate(int year, int month, int day, int hour, int minute, int second, int millisecond, out DateTime result)
1579         {
1580             result = DateTime.MinValue;
1581             if (year < 1 || year > 9999 || month < 1 || month > 12)
1582             {
1583                 return false;
1584             }
1585             int[] days = IsLeapYear(year) ? s_daysToMonth366 : s_daysToMonth365;
1586             if (day < 1 || day > days[month] - days[month - 1])
1587             {
1588                 return false;
1589             }
1590             if (hour < 0 || hour >= 24 || minute < 0 || minute >= 60 || second < 0 || second >= 60)
1591             {
1592                 return false;
1593             }
1594             if (millisecond < 0 || millisecond >= MillisPerSecond)
1595             {
1596                 return false;
1597             }
1598             long ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
1599 
1600             ticks += millisecond * TicksPerMillisecond;
1601             if (ticks < MinTicks || ticks > MaxTicks)
1602             {
1603                 return false;
1604             }
1605             result = new DateTime(ticks, DateTimeKind.Unspecified);
1606             return true;
1607         }
1608     }
1609 }
1610