1 // ==++== 2 // 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // 5 // ==--== 6 namespace System { 7 8 using System; 9 using System.Threading; 10 using System.Globalization; 11 using System.Runtime; 12 using System.Runtime.InteropServices; 13 using System.Runtime.CompilerServices; 14 using System.Runtime.Serialization; 15 using System.Runtime.Versioning; 16 using System.Security; 17 using System.Security.Permissions; 18 using System.Diagnostics.Contracts; 19 using CultureInfo = System.Globalization.CultureInfo; 20 using Calendar = System.Globalization.Calendar; 21 22 // This value type represents a date and time. Every DateTime 23 // object has a private field (Ticks) of type Int64 that stores the 24 // date and time as the number of 100 nanosecond intervals since 25 // 12:00 AM January 1, year 1 A.D. in the proleptic Gregorian Calendar. 26 // 27 // Starting from V2.0, DateTime also stored some context about its time 28 // zone in the form of a 3-state value representing Unspecified, Utc or 29 // Local. This is stored in the two top bits of the 64-bit numeric value 30 // with the remainder of the bits storing the tick count. This information 31 // is only used during time zone conversions and is not part of the 32 // identity of the DateTime. Thus, operations like Compare and Equals 33 // ignore this state. This is to stay compatible with earlier behavior 34 // and performance characteristics and to avoid forcing people into dealing 35 // with the effects of daylight savings. Note, that this has little effect 36 // on how the DateTime works except in a context where its specific time 37 // zone is needed, such as during conversions and some parsing and formatting 38 // cases. 39 // 40 // There is also 4th state stored that is a special type of Local value that 41 // is used to avoid data loss when round-tripping between local and UTC time. 42 // See below for more information on this 4th state, although it is 43 // effectively hidden from most users, who just see the 3-state DateTimeKind 44 // enumeration. 45 // 46 // For compatability, DateTime does not serialize the Kind data when used in 47 // binary serialization. 48 // 49 // For a description of various calendar issues, look at 50 // 51 // Calendar Studies web site, at 52 // http://serendipity.nofadz.com/hermetic/cal_stud.htm. 53 // 54 // 55 [StructLayout(LayoutKind.Auto)] 56 [Serializable] 57 public struct DateTime : IComparable, IFormattable, IConvertible, ISerializable, IComparable<DateTime>,IEquatable<DateTime> { 58 59 // Number of 100ns ticks per time unit 60 private const long TicksPerMillisecond = 10000; 61 private const long TicksPerSecond = TicksPerMillisecond * 1000; 62 private const long TicksPerMinute = TicksPerSecond * 60; 63 private const long TicksPerHour = TicksPerMinute * 60; 64 private const long TicksPerDay = TicksPerHour * 24; 65 66 // Number of milliseconds per time unit 67 private const int MillisPerSecond = 1000; 68 private const int MillisPerMinute = MillisPerSecond * 60; 69 private const int MillisPerHour = MillisPerMinute * 60; 70 private const int MillisPerDay = MillisPerHour * 24; 71 72 // Number of days in a non-leap year 73 private const int DaysPerYear = 365; 74 // Number of days in 4 years 75 private const int DaysPer4Years = DaysPerYear * 4 + 1; // 1461 76 // Number of days in 100 years 77 private const int DaysPer100Years = DaysPer4Years * 25 - 1; // 36524 78 // Number of days in 400 years 79 private const int DaysPer400Years = DaysPer100Years * 4 + 1; // 146097 80 81 // Number of days from 1/1/0001 to 12/31/1600 82 private const int DaysTo1601 = DaysPer400Years * 4; // 584388 83 // Number of days from 1/1/0001 to 12/30/1899 84 private const int DaysTo1899 = DaysPer400Years * 4 + DaysPer100Years * 3 - 367; 85 // Number of days from 1/1/0001 to 12/31/1969 86 internal const int DaysTo1970 = DaysPer400Years * 4 + DaysPer100Years * 3 + DaysPer4Years * 17 + DaysPerYear; // 719,162 87 // Number of days from 1/1/0001 to 12/31/9999 88 private const int DaysTo10000 = DaysPer400Years * 25 - 366; // 3652059 89 90 internal const long MinTicks = 0; 91 internal const long MaxTicks = DaysTo10000 * TicksPerDay - 1; 92 private const long MaxMillis = (long)DaysTo10000 * MillisPerDay; 93 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[] DaysToMonth365 = { 110 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; 111 private static readonly int[] 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 117 private const UInt64 TicksMask = 0x3FFFFFFFFFFFFFFF; 118 private const UInt64 FlagsMask = 0xC000000000000000; 119 private const UInt64 LocalMask = 0x8000000000000000; 120 private const Int64 TicksCeiling = 0x4000000000000000; 121 private const UInt64 KindUnspecified = 0x0000000000000000; 122 private const UInt64 KindUtc = 0x4000000000000000; 123 private const UInt64 KindLocal = 0x8000000000000000; 124 private const UInt64 KindLocalAmbiguousDst = 0xC000000000000000; 125 private const Int32 KindShift = 62; 126 127 private const String TicksField = "ticks"; 128 private const String DateDataField = "dateData"; 129 130 // The data is stored as an unsigned 64-bit integeter 131 // Bits 01-62: The value of 100-nanosecond ticks where 0 represents 1/1/0001 12:00am, up until the value 132 // 12/31/9999 23:59:59.9999999 133 // Bits 63-64: A four-state value that describes the DateTimeKind value of the date time, with a 2nd 134 // value for the rare case where the date time is local, but is in an overlapped daylight 135 // savings time hour and it is in daylight savings time. This allows distinction of these 136 // otherwise ambiguous local times and prevents data loss when round tripping from Local to 137 // UTC time. 138 private UInt64 dateData; 139 140 // Constructs a DateTime from a tick count. The ticks 141 // argument specifies the date as the number of 100-nanosecond intervals 142 // that have elapsed since 1/1/0001 12:00am. 143 // DateTimeSystem.DateTime144 public DateTime(long ticks) { 145 if (ticks < MinTicks || ticks > MaxTicks) 146 throw new ArgumentOutOfRangeException("ticks", Environment.GetResourceString("ArgumentOutOfRange_DateTimeBadTicks")); 147 Contract.EndContractBlock(); 148 dateData = (UInt64)ticks; 149 } 150 DateTimeSystem.DateTime151 private DateTime(UInt64 dateData) { 152 this.dateData = dateData; 153 } 154 DateTimeSystem.DateTime155 public DateTime(long ticks, DateTimeKind kind) { 156 if (ticks < MinTicks || ticks > MaxTicks) { 157 throw new ArgumentOutOfRangeException("ticks", Environment.GetResourceString("ArgumentOutOfRange_DateTimeBadTicks")); 158 } 159 if (kind < DateTimeKind.Unspecified || kind > DateTimeKind.Local) { 160 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidDateTimeKind"), "kind"); 161 } 162 Contract.EndContractBlock(); 163 this.dateData = ((UInt64)ticks | ((UInt64)kind << KindShift)); 164 } 165 DateTimeSystem.DateTime166 internal DateTime(long ticks, DateTimeKind kind, Boolean isAmbiguousDst) { 167 if (ticks < MinTicks || ticks > MaxTicks) { 168 throw new ArgumentOutOfRangeException("ticks", Environment.GetResourceString("ArgumentOutOfRange_DateTimeBadTicks")); 169 } 170 Contract.Requires(kind == DateTimeKind.Local, "Internal Constructor is for local times only"); 171 Contract.EndContractBlock(); 172 dateData = ((UInt64)ticks | (isAmbiguousDst ? KindLocalAmbiguousDst : KindLocal)); 173 } 174 175 // Constructs a DateTime from a given year, month, and day. The 176 // time-of-day of the resulting DateTime is always midnight. 177 // DateTimeSystem.DateTime178 public DateTime(int year, int month, int day) { 179 this.dateData = (UInt64) DateToTicks(year, month, day); 180 } 181 182 // Constructs a DateTime from a given year, month, and day for 183 // the specified calendar. The 184 // time-of-day of the resulting DateTime is always midnight. 185 // DateTimeSystem.DateTime186 public DateTime(int year, int month, int day, Calendar calendar) 187 : this(year, month, day, 0, 0, 0, calendar) { 188 } 189 190 // Constructs a DateTime from a given year, month, day, hour, 191 // minute, and second. 192 // DateTimeSystem.DateTime193 public DateTime(int year, int month, int day, int hour, int minute, int second) { 194 this.dateData = (UInt64)(DateToTicks(year, month, day) + TimeToTicks(hour, minute, second)); 195 } 196 DateTimeSystem.DateTime197 public DateTime(int year, int month, int day, int hour, int minute, int second, DateTimeKind kind) { 198 if (kind < DateTimeKind.Unspecified || kind > DateTimeKind.Local) { 199 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidDateTimeKind"), "kind"); 200 } 201 Contract.EndContractBlock(); 202 Int64 ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second); 203 this.dateData = ((UInt64)ticks | ((UInt64)kind << KindShift)); 204 } 205 206 // Constructs a DateTime from a given year, month, day, hour, 207 // minute, and second for the specified calendar. 208 // DateTimeSystem.DateTime209 public DateTime(int year, int month, int day, int hour, int minute, int second, Calendar calendar) { 210 if (calendar == null) 211 throw new ArgumentNullException("calendar"); 212 Contract.EndContractBlock(); 213 this.dateData = (UInt64)calendar.ToDateTime(year, month, day, hour, minute, second, 0).Ticks; 214 } 215 216 // Constructs a DateTime from a given year, month, day, hour, 217 // minute, and second. 218 // DateTimeSystem.DateTime219 public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond) { 220 if (millisecond < 0 || millisecond >= MillisPerSecond) { 221 throw new ArgumentOutOfRangeException("millisecond", Environment.GetResourceString("ArgumentOutOfRange_Range", 0, MillisPerSecond - 1)); 222 } 223 Contract.EndContractBlock(); 224 Int64 ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second); 225 ticks += millisecond * TicksPerMillisecond; 226 if (ticks < MinTicks || ticks > MaxTicks) 227 throw new ArgumentException(Environment.GetResourceString("Arg_DateTimeRange")); 228 this.dateData = (UInt64)ticks; 229 } 230 DateTimeSystem.DateTime231 public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind) { 232 if (millisecond < 0 || millisecond >= MillisPerSecond) { 233 throw new ArgumentOutOfRangeException("millisecond", Environment.GetResourceString("ArgumentOutOfRange_Range", 0, MillisPerSecond - 1)); 234 } 235 if (kind < DateTimeKind.Unspecified || kind > DateTimeKind.Local) { 236 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidDateTimeKind"), "kind"); 237 } 238 Contract.EndContractBlock(); 239 Int64 ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second); 240 ticks += millisecond * TicksPerMillisecond; 241 if (ticks < MinTicks || ticks > MaxTicks) 242 throw new ArgumentException(Environment.GetResourceString("Arg_DateTimeRange")); 243 this.dateData = ((UInt64)ticks | ((UInt64)kind << KindShift)); 244 } 245 246 // Constructs a DateTime from a given year, month, day, hour, 247 // minute, and second for the specified calendar. 248 // DateTimeSystem.DateTime249 public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar) { 250 if (calendar == null) 251 throw new ArgumentNullException("calendar"); 252 if (millisecond < 0 || millisecond >= MillisPerSecond) { 253 throw new ArgumentOutOfRangeException("millisecond", Environment.GetResourceString("ArgumentOutOfRange_Range", 0, MillisPerSecond - 1)); 254 } 255 Contract.EndContractBlock(); 256 Int64 ticks = calendar.ToDateTime(year, month, day, hour, minute, second, 0).Ticks; 257 ticks += millisecond * TicksPerMillisecond; 258 if (ticks < MinTicks || ticks > MaxTicks) 259 throw new ArgumentException(Environment.GetResourceString("Arg_DateTimeRange")); 260 this.dateData = (UInt64)ticks; 261 } 262 DateTimeSystem.DateTime263 public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, DateTimeKind kind) { 264 if (calendar == null) 265 throw new ArgumentNullException("calendar"); 266 if (millisecond < 0 || millisecond >= MillisPerSecond) { 267 throw new ArgumentOutOfRangeException("millisecond", Environment.GetResourceString("ArgumentOutOfRange_Range", 0, MillisPerSecond - 1)); 268 } 269 if (kind < DateTimeKind.Unspecified || kind > DateTimeKind.Local) { 270 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidDateTimeKind"), "kind"); 271 } 272 Contract.EndContractBlock(); 273 Int64 ticks = calendar.ToDateTime(year, month, day, hour, minute, second, 0).Ticks; 274 ticks += millisecond * TicksPerMillisecond; 275 if (ticks < MinTicks || ticks > MaxTicks) 276 throw new ArgumentException(Environment.GetResourceString("Arg_DateTimeRange")); 277 this.dateData = ((UInt64)ticks | ((UInt64)kind << KindShift)); 278 } 279 DateTimeSystem.DateTime280 private DateTime(SerializationInfo info, StreamingContext context) { 281 if (info==null) 282 throw new ArgumentNullException("info"); 283 Contract.EndContractBlock(); 284 285 Boolean foundTicks = false; 286 Boolean foundDateData = false; 287 Int64 serializedTicks = 0; 288 UInt64 serializedDateData = 0; 289 290 291 // Get the data 292 SerializationInfoEnumerator enumerator = info.GetEnumerator(); 293 while( enumerator.MoveNext()) { 294 switch( enumerator.Name) { 295 case TicksField: 296 serializedTicks = Convert.ToInt64(enumerator.Value, CultureInfo.InvariantCulture); 297 foundTicks = true; 298 break; 299 case DateDataField: 300 serializedDateData = Convert.ToUInt64(enumerator.Value, CultureInfo.InvariantCulture); 301 foundDateData = true; 302 break; 303 default: 304 // Ignore other fields for forward compatability. 305 break; 306 } 307 } 308 if (foundDateData) { 309 this.dateData = serializedDateData; 310 } 311 else if (foundTicks) { 312 this.dateData = (UInt64)serializedTicks; 313 } 314 else { 315 throw new SerializationException(Environment.GetResourceString("Serialization_MissingDateTimeData")); 316 } 317 Int64 ticks = InternalTicks; 318 if (ticks < MinTicks || ticks > MaxTicks) { 319 throw new SerializationException(Environment.GetResourceString("Serialization_DateTimeTicksOutOfRange")); 320 } 321 } 322 323 324 325 internal Int64 InternalTicks { 326 get { 327 return (Int64)(dateData & TicksMask); 328 } 329 } 330 331 private UInt64 InternalKind { 332 get { 333 return (dateData & FlagsMask); 334 } 335 } 336 337 // Returns the DateTime resulting from adding the given 338 // TimeSpan to this DateTime. 339 // AddSystem.DateTime340 public DateTime Add(TimeSpan value) { 341 return AddTicks(value._ticks); 342 } 343 344 // Returns the DateTime resulting from adding a fractional number of 345 // time units to this DateTime. AddSystem.DateTime346 private DateTime Add(double value, int scale) { 347 long millis; 348 try { 349 millis = checked((long)(value * scale + (value >= 0? 0.5: -0.5))); 350 } catch (OverflowException) { 351 throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_AddValue")); 352 } 353 if (millis <= -MaxMillis || millis >= MaxMillis) 354 throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_AddValue")); 355 return AddTicks(millis * TicksPerMillisecond); 356 } 357 358 // Returns the DateTime resulting from adding a fractional number of 359 // days to this DateTime. The result is computed by rounding the 360 // fractional number of days given by value to the nearest 361 // millisecond, and adding that interval to this DateTime. The 362 // value argument is permitted to be negative. 363 // AddDaysSystem.DateTime364 public DateTime AddDays(double value) { 365 return Add(value, MillisPerDay); 366 } 367 368 // Returns the DateTime resulting from adding a fractional number of 369 // hours to this DateTime. The result is computed by rounding the 370 // fractional number of hours given by value to the nearest 371 // millisecond, and adding that interval to this DateTime. The 372 // value argument is permitted to be negative. 373 // AddHoursSystem.DateTime374 public DateTime AddHours(double value) { 375 return Add(value, MillisPerHour); 376 } 377 378 // Returns the DateTime resulting from the given number of 379 // milliseconds to this DateTime. The result is computed by rounding 380 // the number of milliseconds given by value to the nearest integer, 381 // and adding that interval to this DateTime. The value 382 // argument is permitted to be negative. 383 // AddMillisecondsSystem.DateTime384 public DateTime AddMilliseconds(double value) { 385 return Add(value, 1); 386 } 387 388 // Returns the DateTime resulting from adding a fractional number of 389 // minutes to this DateTime. The result is computed by rounding the 390 // fractional number of minutes given by value to the nearest 391 // millisecond, and adding that interval to this DateTime. The 392 // value argument is permitted to be negative. 393 // AddMinutesSystem.DateTime394 public DateTime AddMinutes(double value) { 395 return Add(value, MillisPerMinute); 396 } 397 398 // Returns the DateTime resulting from adding the given number of 399 // months to this DateTime. The result is computed by incrementing 400 // (or decrementing) the year and month parts of this DateTime by 401 // months months, and, if required, adjusting the day part of the 402 // resulting date downwards to the last day of the resulting month in the 403 // resulting year. The time-of-day part of the result is the same as the 404 // time-of-day part of this DateTime. 405 // 406 // In more precise terms, considering this DateTime to be of the 407 // form y / m / d + t, where y is the 408 // year, m is the month, d is the day, and t is the 409 // time-of-day, the result is y1 / m1 / d1 + t, 410 // where y1 and m1 are computed by adding months months 411 // to y and m, and d1 is the largest value less than 412 // or equal to d that denotes a valid day in month m1 of year 413 // y1. 414 // AddMonthsSystem.DateTime415 public DateTime AddMonths(int months) { 416 if (months < -120000 || months > 120000) throw new ArgumentOutOfRangeException("months", Environment.GetResourceString("ArgumentOutOfRange_DateTimeBadMonths")); 417 Contract.EndContractBlock(); 418 int y = GetDatePart(DatePartYear); 419 int m = GetDatePart(DatePartMonth); 420 int d = GetDatePart(DatePartDay); 421 int i = m - 1 + months; 422 if (i >= 0) { 423 m = i % 12 + 1; 424 y = y + i / 12; 425 } 426 else { 427 m = 12 + (i + 1) % 12; 428 y = y + (i - 11) / 12; 429 } 430 if (y < 1 || y > 9999) { 431 throw new ArgumentOutOfRangeException("months", Environment.GetResourceString("ArgumentOutOfRange_DateArithmetic")); 432 } 433 int days = DaysInMonth(y, m); 434 if (d > days) d = days; 435 return new DateTime((UInt64)(DateToTicks(y, m, d) + InternalTicks % TicksPerDay) | InternalKind); 436 } 437 438 // Returns the DateTime resulting from adding a fractional number of 439 // seconds to this DateTime. The result is computed by rounding the 440 // fractional number of seconds given by value to the nearest 441 // millisecond, and adding that interval to this DateTime. The 442 // value argument is permitted to be negative. 443 // AddSecondsSystem.DateTime444 public DateTime AddSeconds(double value) { 445 return Add(value, MillisPerSecond); 446 } 447 448 // Returns the DateTime resulting from adding the given number of 449 // 100-nanosecond ticks to this DateTime. The value argument 450 // is permitted to be negative. 451 // AddTicksSystem.DateTime452 public DateTime AddTicks(long value) { 453 long ticks = InternalTicks; 454 if (value > MaxTicks - ticks || value < MinTicks - ticks) { 455 throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_DateArithmetic")); 456 } 457 return new DateTime((UInt64)(ticks + value) | InternalKind); 458 } 459 460 // Returns the DateTime resulting from adding the given number of 461 // years to this DateTime. The result is computed by incrementing 462 // (or decrementing) the year part of this DateTime by value 463 // years. If the month and day of this DateTime is 2/29, and if the 464 // resulting year is not a leap year, the month and day of the resulting 465 // DateTime becomes 2/28. Otherwise, the month, day, and time-of-day 466 // parts of the result are the same as those of this DateTime. 467 // AddYearsSystem.DateTime468 public DateTime AddYears(int value) { 469 if (value < -10000 || value > 10000) throw new ArgumentOutOfRangeException("years", Environment.GetResourceString("ArgumentOutOfRange_DateTimeBadYears")); 470 Contract.EndContractBlock(); 471 return AddMonths(value * 12); 472 } 473 474 // Compares two DateTime values, returning an integer that indicates 475 // their relationship. 476 // CompareSystem.DateTime477 public static int Compare(DateTime t1, DateTime t2) { 478 Int64 ticks1 = t1.InternalTicks; 479 Int64 ticks2 = t2.InternalTicks; 480 if (ticks1 > ticks2) return 1; 481 if (ticks1 < ticks2) return -1; 482 return 0; 483 } 484 485 // Compares this DateTime to a given object. This method provides an 486 // implementation of the IComparable interface. The object 487 // argument must be another DateTime, or otherwise an exception 488 // occurs. Null is considered less than any instance. 489 // 490 // Returns a value less than zero if this object CompareToSystem.DateTime491 public int CompareTo(Object value) { 492 if (value == null) return 1; 493 if (!(value is DateTime)) { 494 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDateTime")); 495 } 496 497 long valueTicks = ((DateTime)value).InternalTicks; 498 long ticks = InternalTicks; 499 if (ticks > valueTicks) return 1; 500 if (ticks < valueTicks) return -1; 501 return 0; 502 } 503 CompareToSystem.DateTime504 public int CompareTo(DateTime value) { 505 long valueTicks = value.InternalTicks; 506 long ticks = InternalTicks; 507 if (ticks > valueTicks) return 1; 508 if (ticks < valueTicks) return -1; 509 return 0; 510 } 511 512 // Returns the tick count corresponding to the given year, month, and day. 513 // Will check the if the parameters are valid. DateToTicksSystem.DateTime514 private static long DateToTicks(int year, int month, int day) { 515 if (year >= 1 && year <= 9999 && month >= 1 && month <= 12) { 516 int[] days = IsLeapYear(year)? DaysToMonth366: DaysToMonth365; 517 if (day >= 1 && day <= days[month] - days[month - 1]) { 518 int y = year - 1; 519 int n = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1; 520 return n * TicksPerDay; 521 } 522 } 523 throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_BadYearMonthDay")); 524 } 525 526 // Return the tick count corresponding to the given hour, minute, second. 527 // Will check the if the parameters are valid. TimeToTicksSystem.DateTime528 private static long TimeToTicks(int hour, int minute, int second) 529 { 530 //TimeSpan.TimeToTicks is a family access function which does no error checking, so 531 //we need to put some error checking out here. 532 if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >=0 && second < 60) 533 { 534 return (TimeSpan.TimeToTicks(hour, minute, second)); 535 } 536 throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_BadHourMinuteSecond")); 537 } 538 539 // Returns the number of days in the month given by the year and 540 // month arguments. 541 // DaysInMonthSystem.DateTime542 public static int DaysInMonth(int year, int month) { 543 if (month < 1 || month > 12) throw new ArgumentOutOfRangeException("month", Environment.GetResourceString("ArgumentOutOfRange_Month")); 544 Contract.EndContractBlock(); 545 // IsLeapYear checks the year argument 546 int[] days = IsLeapYear(year)? DaysToMonth366: DaysToMonth365; 547 return days[month] - days[month - 1]; 548 } 549 550 // Converts an OLE Date to a tick count. 551 // This function is duplicated in COMDateTime.cpp DoubleDateToTicksSystem.DateTime552 internal static long DoubleDateToTicks(double value) { 553 // The check done this way will take care of NaN 554 if (!(value < OADateMaxAsDouble) || !(value > OADateMinAsDouble)) 555 throw new ArgumentException(Environment.GetResourceString("Arg_OleAutDateInvalid")); 556 557 // Conversion to long will not cause an overflow here, as at this point the "value" is in between OADateMinAsDouble and OADateMaxAsDouble 558 long millis = (long)(value * MillisPerDay + (value >= 0? 0.5: -0.5)); 559 // 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 560 // 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 561 // This line below fixes up the millis in the negative case 562 if (millis < 0) { 563 millis -= (millis % MillisPerDay) * 2; 564 } 565 566 millis += DoubleDateOffset / TicksPerMillisecond; 567 568 if (millis < 0 || millis >= MaxMillis) throw new ArgumentException(Environment.GetResourceString("Arg_OleAutDateScale")); 569 return millis * TicksPerMillisecond; 570 } 571 572 #if !FEATURE_CORECLR && !MONO 573 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] 574 [SecurityCritical] 575 [ResourceExposure(ResourceScope.None)] 576 [SuppressUnmanagedCodeSecurity] 577 [return: MarshalAs(UnmanagedType.Bool)] LegacyParseModeSystem.DateTime578 internal static extern bool LegacyParseMode(); 579 580 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] 581 [SecurityCritical] 582 [ResourceExposure(ResourceScope.None)] 583 [SuppressUnmanagedCodeSecurity] 584 [return: MarshalAs(UnmanagedType.Bool)] EnableAmPmParseAdjustmentSystem.DateTime585 internal static extern bool EnableAmPmParseAdjustment(); 586 #endif 587 588 // Checks if this DateTime is equal to a given object. Returns 589 // true if the given object is a boxed DateTime and its value 590 // is equal to the value of this DateTime. Returns false 591 // otherwise. 592 // EqualsSystem.DateTime593 public override bool Equals(Object value) { 594 if (value is DateTime) { 595 return InternalTicks == ((DateTime)value).InternalTicks; 596 } 597 return false; 598 } 599 EqualsSystem.DateTime600 public bool Equals(DateTime value) { 601 return InternalTicks == value.InternalTicks; 602 } 603 604 // Compares two DateTime values for equality. Returns true if 605 // the two DateTime values are equal, or false if they are 606 // not equal. 607 // EqualsSystem.DateTime608 public static bool Equals(DateTime t1, DateTime t2) { 609 return t1.InternalTicks == t2.InternalTicks; 610 } 611 FromBinarySystem.DateTime612 public static DateTime FromBinary(Int64 dateData) { 613 if ((dateData & (unchecked( (Int64) LocalMask))) != 0) { 614 // Local times need to be adjusted as you move from one time zone to another, 615 // just as they are when serializing in text. As such the format for local times 616 // changes to store the ticks of the UTC time, but with flags that look like a 617 // local date. 618 Int64 ticks = dateData & (unchecked((Int64)TicksMask)); 619 // Negative ticks are stored in the top part of the range and should be converted back into a negative number 620 if (ticks > TicksCeiling - TicksPerDay) { 621 ticks = ticks - TicksCeiling; 622 } 623 // Convert the ticks back to local. If the UTC ticks are out of range, we need to default to 624 // the UTC offset from MinValue and MaxValue to be consistent with Parse. 625 Boolean isAmbiguousLocalDst = false; 626 Int64 offsetTicks; 627 if (ticks < MinTicks) { 628 offsetTicks = TimeZoneInfo.GetLocalUtcOffset(DateTime.MinValue, TimeZoneInfoOptions.NoThrowOnInvalidTime).Ticks; 629 } 630 else if (ticks > MaxTicks) { 631 offsetTicks = TimeZoneInfo.GetLocalUtcOffset(DateTime.MaxValue, TimeZoneInfoOptions.NoThrowOnInvalidTime).Ticks; 632 } 633 else { 634 // Because the ticks conversion between UTC and local is lossy, we need to capture whether the 635 // time is in a repeated hour so that it can be passed to the DateTime constructor. 636 DateTime utcDt = new DateTime(ticks, DateTimeKind.Utc); 637 Boolean isDaylightSavings = false; 638 offsetTicks = TimeZoneInfo.GetUtcOffsetFromUtc(utcDt, TimeZoneInfo.Local, out isDaylightSavings, out isAmbiguousLocalDst).Ticks; 639 } 640 ticks += offsetTicks; 641 // Another behaviour of parsing is to cause small times to wrap around, so that they can be used 642 // to compare times of day 643 if (ticks < 0) { 644 ticks += TicksPerDay; 645 } 646 if (ticks < MinTicks || ticks > MaxTicks) { 647 throw new ArgumentException(Environment.GetResourceString("Argument_DateTimeBadBinaryData"), "dateData"); 648 } 649 return new DateTime(ticks, DateTimeKind.Local, isAmbiguousLocalDst); 650 } 651 else { 652 return DateTime.FromBinaryRaw(dateData); 653 } 654 } 655 656 // A version of ToBinary that uses the real representation and does not adjust local times. This is needed for 657 // scenarios where the serialized data must maintain compatability FromBinaryRawSystem.DateTime658 internal static DateTime FromBinaryRaw(Int64 dateData) { 659 Int64 ticks = dateData & (Int64)TicksMask; 660 if (ticks < MinTicks || ticks > MaxTicks) 661 throw new ArgumentException(Environment.GetResourceString("Argument_DateTimeBadBinaryData"), "dateData"); 662 return new DateTime((UInt64)dateData); 663 } 664 665 // Creates a DateTime from a Windows filetime. A Windows filetime is 666 // a long representing the date and time as the number of 667 // 100-nanosecond intervals that have elapsed since 1/1/1601 12:00am. 668 // FromFileTimeSystem.DateTime669 public static DateTime FromFileTime(long fileTime) { 670 return FromFileTimeUtc(fileTime).ToLocalTime(); 671 } 672 FromFileTimeUtcSystem.DateTime673 public static DateTime FromFileTimeUtc(long fileTime) { 674 if (fileTime < 0 || fileTime > MaxTicks - FileTimeOffset) { 675 throw new ArgumentOutOfRangeException("fileTime", Environment.GetResourceString("ArgumentOutOfRange_FileTimeInvalid")); 676 } 677 Contract.EndContractBlock(); 678 679 // This is the ticks in Universal time for this fileTime. 680 long universalTicks = fileTime + FileTimeOffset; 681 return new DateTime(universalTicks, DateTimeKind.Utc); 682 } 683 684 // Creates a DateTime from an OLE Automation Date. 685 // FromOADateSystem.DateTime686 public static DateTime FromOADate(double d) { 687 return new DateTime(DoubleDateToTicks(d), DateTimeKind.Unspecified); 688 } 689 690 #if FEATURE_SERIALIZATION 691 [System.Security.SecurityCritical /*auto-generated_required*/] ISerializable.GetObjectDataSystem.DateTime692 void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { 693 if (info==null) { 694 throw new ArgumentNullException("info"); 695 } 696 Contract.EndContractBlock(); 697 698 // Serialize both the old and the new format 699 info.AddValue(TicksField, InternalTicks); 700 info.AddValue(DateDataField, dateData); 701 } 702 #endif 703 IsDaylightSavingTimeSystem.DateTime704 public Boolean IsDaylightSavingTime() { 705 if (Kind == DateTimeKind.Utc) { 706 return false; 707 } 708 return TimeZoneInfo.Local.IsDaylightSavingTime(this, TimeZoneInfoOptions.NoThrowOnInvalidTime); 709 } 710 SpecifyKindSystem.DateTime711 public static DateTime SpecifyKind(DateTime value, DateTimeKind kind) { 712 return new DateTime(value.InternalTicks, kind); 713 } 714 ToBinarySystem.DateTime715 public Int64 ToBinary() { 716 if (Kind == DateTimeKind.Local) { 717 // Local times need to be adjusted as you move from one time zone to another, 718 // just as they are when serializing in text. As such the format for local times 719 // changes to store the ticks of the UTC time, but with flags that look like a 720 // local date. 721 722 // To match serialization in text we need to be able to handle cases where 723 // the UTC value would be out of range. Unused parts of the ticks range are 724 // used for this, so that values just past max value are stored just past the 725 // end of the maximum range, and values just below minimum value are stored 726 // at the end of the ticks area, just below 2^62. 727 TimeSpan offset = TimeZoneInfo.GetLocalUtcOffset(this, TimeZoneInfoOptions.NoThrowOnInvalidTime); 728 Int64 ticks = Ticks; 729 Int64 storedTicks = ticks - offset.Ticks; 730 if (storedTicks < 0) { 731 storedTicks = TicksCeiling + storedTicks; 732 } 733 return storedTicks | (unchecked((Int64) LocalMask)); 734 } 735 else { 736 return (Int64)dateData; 737 } 738 } 739 740 // Return the underlying data, without adjust local times to the right time zone. Needed if performance 741 // or compatability are important. ToBinaryRawSystem.DateTime742 internal Int64 ToBinaryRaw() { 743 return (Int64)dateData; 744 } 745 746 // Returns the date part of this DateTime. The resulting value 747 // corresponds to this DateTime with the time-of-day part set to 748 // zero (midnight). 749 // 750 public DateTime Date { 751 get { 752 Int64 ticks = InternalTicks; 753 return new DateTime((UInt64)(ticks - ticks % TicksPerDay) | InternalKind); 754 } 755 } 756 757 // Returns a given date part of this DateTime. This method is used 758 // to compute the year, day-of-year, month, or day part. GetDatePartSystem.DateTime759 private int GetDatePart(int part) { 760 Int64 ticks = InternalTicks; 761 // n = number of days since 1/1/0001 762 int n = (int)(ticks / TicksPerDay); 763 // y400 = number of whole 400-year periods since 1/1/0001 764 int y400 = n / DaysPer400Years; 765 // n = day number within 400-year period 766 n -= y400 * DaysPer400Years; 767 // y100 = number of whole 100-year periods within 400-year period 768 int y100 = n / DaysPer100Years; 769 // Last 100-year period has an extra day, so decrement result if 4 770 if (y100 == 4) y100 = 3; 771 // n = day number within 100-year period 772 n -= y100 * DaysPer100Years; 773 // y4 = number of whole 4-year periods within 100-year period 774 int y4 = n / DaysPer4Years; 775 // n = day number within 4-year period 776 n -= y4 * DaysPer4Years; 777 // y1 = number of whole years within 4-year period 778 int y1 = n / DaysPerYear; 779 // Last year has an extra day, so decrement result if 4 780 if (y1 == 4) y1 = 3; 781 // If year was requested, compute and return it 782 if (part == DatePartYear) { 783 return y400 * 400 + y100 * 100 + y4 * 4 + y1 + 1; 784 } 785 // n = day number within year 786 n -= y1 * DaysPerYear; 787 // If day-of-year was requested, return it 788 if (part == DatePartDayOfYear) return n + 1; 789 // Leap year calculation looks different from IsLeapYear since y1, y4, 790 // and y100 are relative to year 1, not year 0 791 bool leapYear = y1 == 3 && (y4 != 24 || y100 == 3); 792 int[] days = leapYear? DaysToMonth366: DaysToMonth365; 793 // All months have less than 32 days, so n >> 5 is a good conservative 794 // estimate for the month 795 int m = n >> 5 + 1; 796 // m = 1-based month number 797 while (n >= days[m]) m++; 798 // If month was requested, return it 799 if (part == DatePartMonth) return m; 800 // Return 1-based day-of-month 801 return n - days[m - 1] + 1; 802 } 803 804 // Returns the day-of-month part of this DateTime. The returned 805 // value is an integer between 1 and 31. 806 // 807 public int Day { 808 get { 809 Contract.Ensures(Contract.Result<int>() >= 1); 810 Contract.Ensures(Contract.Result<int>() <= 31); 811 return GetDatePart(DatePartDay); 812 } 813 } 814 815 // Returns the day-of-week part of this DateTime. The returned value 816 // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates 817 // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates 818 // Thursday, 5 indicates Friday, and 6 indicates Saturday. 819 // 820 public DayOfWeek DayOfWeek { 821 get { 822 Contract.Ensures(Contract.Result<DayOfWeek>() >= DayOfWeek.Sunday); 823 Contract.Ensures(Contract.Result<DayOfWeek>() <= DayOfWeek.Saturday); 824 return (DayOfWeek)((InternalTicks / TicksPerDay + 1) % 7); 825 } 826 } 827 828 // Returns the day-of-year part of this DateTime. The returned value 829 // is an integer between 1 and 366. 830 // 831 public int DayOfYear { 832 get { 833 Contract.Ensures(Contract.Result<int>() >= 1); 834 Contract.Ensures(Contract.Result<int>() <= 366); // leap year 835 return GetDatePart(DatePartDayOfYear); 836 } 837 } 838 839 // Returns the hash code for this DateTime. 840 // GetHashCodeSystem.DateTime841 public override int GetHashCode() { 842 Int64 ticks = InternalTicks; 843 return unchecked((int)ticks) ^ (int)(ticks >> 32); 844 } 845 846 // Returns the hour part of this DateTime. The returned value is an 847 // integer between 0 and 23. 848 // 849 public int Hour { 850 get { 851 Contract.Ensures(Contract.Result<int>() >= 0); 852 Contract.Ensures(Contract.Result<int>() < 24); 853 return (int)((InternalTicks / TicksPerHour) % 24); 854 } 855 } 856 IsAmbiguousDaylightSavingTimeSystem.DateTime857 internal Boolean IsAmbiguousDaylightSavingTime() { 858 return (InternalKind == KindLocalAmbiguousDst); 859 } 860 861 [Pure] 862 public DateTimeKind Kind { 863 get { 864 switch (InternalKind) { 865 case KindUnspecified: 866 return DateTimeKind.Unspecified; 867 case KindUtc: 868 return DateTimeKind.Utc; 869 default: 870 return DateTimeKind.Local; 871 } 872 } 873 } 874 875 // Returns the millisecond part of this DateTime. The returned value 876 // is an integer between 0 and 999. 877 // 878 public int Millisecond { 879 get { 880 Contract.Ensures(Contract.Result<int>() >= 0); 881 Contract.Ensures(Contract.Result<int>() < 1000); 882 return (int)((InternalTicks/ TicksPerMillisecond) % 1000); 883 } 884 } 885 886 // Returns the minute part of this DateTime. The returned value is 887 // an integer between 0 and 59. 888 // 889 public int Minute { 890 get { 891 Contract.Ensures(Contract.Result<int>() >= 0); 892 Contract.Ensures(Contract.Result<int>() < 60); 893 return (int)((InternalTicks / TicksPerMinute) % 60); 894 } 895 } 896 897 // Returns the month part of this DateTime. The returned value is an 898 // integer between 1 and 12. 899 // 900 public int Month { 901 get { 902 Contract.Ensures(Contract.Result<int>() >= 1); 903 return GetDatePart(DatePartMonth); 904 } 905 } 906 907 // Returns a DateTime representing the current date and time. The 908 // resolution of the returned value depends on the system timer. For 909 // Windows NT 3.5 and later the timer resolution is approximately 10ms, 910 // for Windows NT 3.1 it is approximately 16ms, and for Windows 95 and 98 911 // it is approximately 55ms. 912 // 913 public static DateTime Now { 914 get { 915 Contract.Ensures(Contract.Result<DateTime>().Kind == DateTimeKind.Local); 916 917 DateTime utc = UtcNow; 918 Boolean isAmbiguousLocalDst = false; 919 Int64 offset = TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc(utc, out isAmbiguousLocalDst).Ticks; 920 long tick = utc.Ticks + offset; 921 if (tick>DateTime.MaxTicks) { 922 return new DateTime(DateTime.MaxTicks, DateTimeKind.Local); 923 } 924 if (tick<DateTime.MinTicks) { 925 return new DateTime(DateTime.MinTicks, DateTimeKind.Local); 926 } 927 return new DateTime(tick, DateTimeKind.Local, isAmbiguousLocalDst); 928 } 929 } 930 931 public static DateTime UtcNow { 932 [System.Security.SecuritySafeCritical] // auto-generated 933 get { 934 Contract.Ensures(Contract.Result<DateTime>().Kind == DateTimeKind.Utc); 935 // following code is tuned for speed. Don't change it without running benchmark. 936 long ticks = 0; 937 ticks = GetSystemTimeAsFileTime(); 938 939 #if FEATURE_LEGACYNETCF 940 // Windows Phone 7.0/7.1 return the ticks up to millisecond, not up to the 100th nanosecond. 941 if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) 942 { 943 long ticksms = ticks / TicksPerMillisecond; 944 ticks = ticksms * TicksPerMillisecond; 945 } 946 #endif 947 return new DateTime( ((UInt64)(ticks + FileTimeOffset)) | KindUtc); 948 } 949 } 950 951 952 [System.Security.SecurityCritical] // auto-generated 953 [MethodImplAttribute(MethodImplOptions.InternalCall)] GetSystemTimeAsFileTimeSystem.DateTime954 internal static extern long GetSystemTimeAsFileTime(); 955 956 957 958 // Returns the second part of this DateTime. The returned value is 959 // an integer between 0 and 59. 960 // 961 public int Second { 962 get { 963 Contract.Ensures(Contract.Result<int>() >= 0); 964 Contract.Ensures(Contract.Result<int>() < 60); 965 return (int)((InternalTicks / TicksPerSecond) % 60); 966 } 967 } 968 969 // Returns the tick count for this DateTime. The returned value is 970 // the number of 100-nanosecond intervals that have elapsed since 1/1/0001 971 // 12:00am. 972 // 973 public long Ticks { 974 get { 975 return InternalTicks; 976 } 977 } 978 979 // Returns the time-of-day part of this DateTime. The returned value 980 // is a TimeSpan that indicates the time elapsed since midnight. 981 // 982 public TimeSpan TimeOfDay { 983 get { 984 return new TimeSpan(InternalTicks % TicksPerDay); 985 } 986 } 987 988 // Returns a DateTime representing the current date. The date part 989 // of the returned value is the current date, and the time-of-day part of 990 // the returned value is zero (midnight). 991 // 992 public static DateTime Today { 993 get { 994 return DateTime.Now.Date; 995 } 996 } 997 998 // Returns the year part of this DateTime. The returned value is an 999 // integer between 1 and 9999. 1000 // 1001 public int Year { 1002 get { 1003 Contract.Ensures(Contract.Result<int>() >= 1 && Contract.Result<int>() <= 9999); 1004 return GetDatePart(DatePartYear); 1005 } 1006 } 1007 1008 // Checks whether a given year is a leap year. This method returns true if 1009 // year is a leap year, or false if not. 1010 // IsLeapYearSystem.DateTime1011 public static bool IsLeapYear(int year) { 1012 if (year < 1 || year > 9999) { 1013 throw new ArgumentOutOfRangeException("year", Environment.GetResourceString("ArgumentOutOfRange_Year")); 1014 } 1015 Contract.EndContractBlock(); 1016 return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); 1017 } 1018 1019 // Constructs a DateTime from a string. The string must specify a 1020 // date and optionally a time in a culture-specific or universal format. 1021 // Leading and trailing whitespace characters are allowed. 1022 // ParseSystem.DateTime1023 public static DateTime Parse(String s) { 1024 return (DateTimeParse.Parse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None)); 1025 } 1026 1027 // Constructs a DateTime from a string. The string must specify a 1028 // date and optionally a time in a culture-specific or universal format. 1029 // Leading and trailing whitespace characters are allowed. 1030 // ParseSystem.DateTime1031 public static DateTime Parse(String s, IFormatProvider provider) { 1032 return (DateTimeParse.Parse(s, DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None)); 1033 } 1034 ParseSystem.DateTime1035 public static DateTime Parse(String s, IFormatProvider provider, DateTimeStyles styles) { 1036 DateTimeFormatInfo.ValidateStyles(styles, "styles"); 1037 return (DateTimeParse.Parse(s, DateTimeFormatInfo.GetInstance(provider), styles)); 1038 } 1039 1040 // Constructs a DateTime from a string. The string must specify a 1041 // date and optionally a time in a culture-specific or universal format. 1042 // Leading and trailing whitespace characters are allowed. 1043 // ParseExactSystem.DateTime1044 public static DateTime ParseExact(String s, String format, IFormatProvider provider) { 1045 return (DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None)); 1046 } 1047 1048 // Constructs a DateTime from a string. The string must specify a 1049 // date and optionally a time in a culture-specific or universal format. 1050 // Leading and trailing whitespace characters are allowed. 1051 // ParseExactSystem.DateTime1052 public static DateTime ParseExact(String s, String format, IFormatProvider provider, DateTimeStyles style) { 1053 DateTimeFormatInfo.ValidateStyles(style, "style"); 1054 return (DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style)); 1055 } 1056 ParseExactSystem.DateTime1057 public static DateTime ParseExact(String s, String[] formats, IFormatProvider provider, DateTimeStyles style) { 1058 DateTimeFormatInfo.ValidateStyles(style, "style"); 1059 return DateTimeParse.ParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style); 1060 } 1061 SubtractSystem.DateTime1062 public TimeSpan Subtract(DateTime value) { 1063 return new TimeSpan(InternalTicks - value.InternalTicks); 1064 } 1065 SubtractSystem.DateTime1066 public DateTime Subtract(TimeSpan value) { 1067 long ticks = InternalTicks; 1068 long valueTicks = value._ticks; 1069 if (ticks - MinTicks < valueTicks || ticks - MaxTicks > valueTicks) { 1070 throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_DateArithmetic")); 1071 } 1072 return new DateTime((UInt64)(ticks - valueTicks) | InternalKind); 1073 } 1074 1075 // This function is duplicated in COMDateTime.cpp TicksToOADateSystem.DateTime1076 private static double TicksToOADate(long value) { 1077 if (value == 0) 1078 return 0.0; // Returns OleAut's zero'ed date value. 1079 if (value < TicksPerDay) // This is a fix for VB. They want the default day to be 1/1/0001 rathar then 12/30/1899. 1080 value += DoubleDateOffset; // We could have moved this fix down but we would like to keep the bounds check. 1081 if (value < OADateMinAsTicks) 1082 throw new OverflowException(Environment.GetResourceString("Arg_OleAutDateInvalid")); 1083 // Currently, our max date == OA's max date (12/31/9999), so we don't 1084 // need an overflow check in that direction. 1085 long millis = (value - DoubleDateOffset) / TicksPerMillisecond; 1086 if (millis < 0) { 1087 long frac = millis % MillisPerDay; 1088 if (frac != 0) millis -= (MillisPerDay + frac) * 2; 1089 } 1090 return (double)millis / MillisPerDay; 1091 } 1092 1093 // Converts the DateTime instance into an OLE Automation compatible 1094 // double date. ToOADateSystem.DateTime1095 public double ToOADate() { 1096 return TicksToOADate(InternalTicks); 1097 } 1098 ToFileTimeSystem.DateTime1099 public long ToFileTime() { 1100 // Treats the input as local if it is not specified 1101 return ToUniversalTime().ToFileTimeUtc(); 1102 } 1103 ToFileTimeUtcSystem.DateTime1104 public long ToFileTimeUtc() { 1105 // Treats the input as universal if it is not specified 1106 long ticks = ((InternalKind & LocalMask) != 0) ? ToUniversalTime().InternalTicks : this.InternalTicks; 1107 ticks -= FileTimeOffset; 1108 if (ticks < 0) { 1109 throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_FileTimeInvalid")); 1110 } 1111 return ticks; 1112 } 1113 ToLocalTimeSystem.DateTime1114 public DateTime ToLocalTime() 1115 { 1116 return ToLocalTime(false); 1117 } 1118 ToLocalTimeSystem.DateTime1119 internal DateTime ToLocalTime(bool throwOnOverflow) 1120 { 1121 if (Kind == DateTimeKind.Local) { 1122 return this; 1123 } 1124 Boolean isDaylightSavings = false; 1125 Boolean isAmbiguousLocalDst = false; 1126 Int64 offset = TimeZoneInfo.GetUtcOffsetFromUtc(this, TimeZoneInfo.Local, out isDaylightSavings, out isAmbiguousLocalDst).Ticks; 1127 long tick = Ticks + offset; 1128 if (tick > DateTime.MaxTicks) 1129 { 1130 if (throwOnOverflow) 1131 throw new ArgumentException(Environment.GetResourceString("Arg_ArgumentOutOfRangeException")); 1132 else 1133 return new DateTime(DateTime.MaxTicks, DateTimeKind.Local); 1134 } 1135 if (tick < DateTime.MinTicks) 1136 { 1137 if (throwOnOverflow) 1138 throw new ArgumentException(Environment.GetResourceString("Arg_ArgumentOutOfRangeException")); 1139 else 1140 return new DateTime(DateTime.MinTicks, DateTimeKind.Local); 1141 } 1142 return new DateTime(tick, DateTimeKind.Local, isAmbiguousLocalDst); 1143 } 1144 ToLongDateStringSystem.DateTime1145 public String ToLongDateString() { 1146 Contract.Ensures(Contract.Result<String>() != null); 1147 return DateTimeFormat.Format(this, "D", DateTimeFormatInfo.CurrentInfo); 1148 } 1149 ToLongTimeStringSystem.DateTime1150 public String ToLongTimeString() { 1151 Contract.Ensures(Contract.Result<String>() != null); 1152 return DateTimeFormat.Format(this, "T", DateTimeFormatInfo.CurrentInfo); 1153 } 1154 ToShortDateStringSystem.DateTime1155 public String ToShortDateString() { 1156 Contract.Ensures(Contract.Result<String>() != null); 1157 return DateTimeFormat.Format(this, "d", DateTimeFormatInfo.CurrentInfo); 1158 } 1159 ToShortTimeStringSystem.DateTime1160 public String ToShortTimeString() { 1161 Contract.Ensures(Contract.Result<String>() != null); 1162 return DateTimeFormat.Format(this, "t", DateTimeFormatInfo.CurrentInfo); 1163 } 1164 ToStringSystem.DateTime1165 public override String ToString() { 1166 Contract.Ensures(Contract.Result<String>() != null); 1167 return DateTimeFormat.Format(this, null, DateTimeFormatInfo.CurrentInfo); 1168 } 1169 ToStringSystem.DateTime1170 public String ToString(String format) { 1171 Contract.Ensures(Contract.Result<String>() != null); 1172 return DateTimeFormat.Format(this, format, DateTimeFormatInfo.CurrentInfo); 1173 } 1174 ToStringSystem.DateTime1175 public String ToString(IFormatProvider provider) { 1176 Contract.Ensures(Contract.Result<String>() != null); 1177 return DateTimeFormat.Format(this, null, DateTimeFormatInfo.GetInstance(provider)); 1178 } 1179 ToStringSystem.DateTime1180 public String ToString(String format, IFormatProvider provider) { 1181 Contract.Ensures(Contract.Result<String>() != null); 1182 return DateTimeFormat.Format(this, format, DateTimeFormatInfo.GetInstance(provider)); 1183 } 1184 ToUniversalTimeSystem.DateTime1185 public DateTime ToUniversalTime() { 1186 return TimeZoneInfo.ConvertTimeToUtc(this, TimeZoneInfoOptions.NoThrowOnInvalidTime); 1187 } 1188 TryParseSystem.DateTime1189 public static Boolean TryParse(String s, out DateTime result) { 1190 return DateTimeParse.TryParse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out result); 1191 } 1192 TryParseSystem.DateTime1193 public static Boolean TryParse(String s, IFormatProvider provider, DateTimeStyles styles, out DateTime result) { 1194 DateTimeFormatInfo.ValidateStyles(styles, "styles"); 1195 return DateTimeParse.TryParse(s, DateTimeFormatInfo.GetInstance(provider), styles, out result); 1196 } 1197 TryParseExactSystem.DateTime1198 public static Boolean TryParseExact(String s, String format, IFormatProvider provider, DateTimeStyles style, out DateTime result) { 1199 DateTimeFormatInfo.ValidateStyles(style, "style"); 1200 return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result); 1201 } 1202 TryParseExactSystem.DateTime1203 public static Boolean TryParseExact(String s, String[] formats, IFormatProvider provider, DateTimeStyles style, out DateTime result) { 1204 DateTimeFormatInfo.ValidateStyles(style, "style"); 1205 return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result); 1206 } 1207 operator +System.DateTime1208 public static DateTime operator +(DateTime d, TimeSpan t) { 1209 long ticks = d.InternalTicks; 1210 long valueTicks = t._ticks; 1211 if (valueTicks > MaxTicks - ticks || valueTicks < MinTicks - ticks) { 1212 throw new ArgumentOutOfRangeException("t", Environment.GetResourceString("ArgumentOutOfRange_DateArithmetic")); 1213 } 1214 return new DateTime((UInt64)(ticks + valueTicks) | d.InternalKind); 1215 } 1216 operator -System.DateTime1217 public static DateTime operator -(DateTime d, TimeSpan t) { 1218 long ticks = d.InternalTicks; 1219 long valueTicks = t._ticks; 1220 if (ticks - MinTicks < valueTicks || ticks - MaxTicks > valueTicks) { 1221 throw new ArgumentOutOfRangeException("t", Environment.GetResourceString("ArgumentOutOfRange_DateArithmetic")); 1222 } 1223 return new DateTime((UInt64)(ticks - valueTicks) | d.InternalKind); 1224 } 1225 operator -System.DateTime1226 public static TimeSpan operator -(DateTime d1, DateTime d2) { 1227 return new TimeSpan(d1.InternalTicks - d2.InternalTicks); 1228 } 1229 operator ==System.DateTime1230 public static bool operator ==(DateTime d1, DateTime d2) { 1231 return d1.InternalTicks == d2.InternalTicks; 1232 } 1233 operator !=System.DateTime1234 public static bool operator !=(DateTime d1, DateTime d2) { 1235 return d1.InternalTicks != d2.InternalTicks; 1236 } 1237 operator <System.DateTime1238 public static bool operator <(DateTime t1, DateTime t2) { 1239 return t1.InternalTicks < t2.InternalTicks; 1240 } 1241 operator <=System.DateTime1242 public static bool operator <=(DateTime t1, DateTime t2) { 1243 return t1.InternalTicks <= t2.InternalTicks; 1244 } 1245 operator >System.DateTime1246 public static bool operator >(DateTime t1, DateTime t2) { 1247 return t1.InternalTicks > t2.InternalTicks; 1248 } 1249 operator >=System.DateTime1250 public static bool operator >=(DateTime t1, DateTime t2) { 1251 return t1.InternalTicks >= t2.InternalTicks; 1252 } 1253 1254 1255 // Returns a string array containing all of the known date and time options for the 1256 // current culture. The strings returned are properly formatted date and 1257 // time strings for the current instance of DateTime. GetDateTimeFormatsSystem.DateTime1258 public String[] GetDateTimeFormats() 1259 { 1260 Contract.Ensures(Contract.Result<String[]>() != null); 1261 return (GetDateTimeFormats(CultureInfo.CurrentCulture)); 1262 } 1263 1264 // Returns a string array containing all of the known date and time options for the 1265 // using the information provided by IFormatProvider. The strings returned are properly formatted date and 1266 // time strings for the current instance of DateTime. GetDateTimeFormatsSystem.DateTime1267 public String[] GetDateTimeFormats(IFormatProvider provider) 1268 { 1269 Contract.Ensures(Contract.Result<String[]>() != null); 1270 return (DateTimeFormat.GetAllDateTimes(this, DateTimeFormatInfo.GetInstance(provider))); 1271 } 1272 1273 1274 // Returns a string array containing all of the date and time options for the 1275 // given format format and current culture. The strings returned are properly formatted date and 1276 // time strings for the current instance of DateTime. GetDateTimeFormatsSystem.DateTime1277 public String[] GetDateTimeFormats(char format) 1278 { 1279 Contract.Ensures(Contract.Result<String[]>() != null); 1280 return (GetDateTimeFormats(format, CultureInfo.CurrentCulture)); 1281 } 1282 1283 // Returns a string array containing all of the date and time options for the 1284 // given format format and given culture. The strings returned are properly formatted date and 1285 // time strings for the current instance of DateTime. GetDateTimeFormatsSystem.DateTime1286 public String[] GetDateTimeFormats(char format, IFormatProvider provider) 1287 { 1288 Contract.Ensures(Contract.Result<String[]>() != null); 1289 return (DateTimeFormat.GetAllDateTimes(this, format, DateTimeFormatInfo.GetInstance(provider))); 1290 } 1291 1292 // 1293 // IConvertible implementation 1294 // 1295 GetTypeCodeSystem.DateTime1296 public TypeCode GetTypeCode() { 1297 return TypeCode.DateTime; 1298 } 1299 1300 1301 /// <internalonly/> IConvertible.ToBooleanSystem.DateTime1302 bool IConvertible.ToBoolean(IFormatProvider provider) { 1303 throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "DateTime", "Boolean")); 1304 } 1305 1306 /// <internalonly/> IConvertible.ToCharSystem.DateTime1307 char IConvertible.ToChar(IFormatProvider provider) { 1308 throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "DateTime", "Char")); 1309 } 1310 1311 /// <internalonly/> IConvertible.ToSByteSystem.DateTime1312 sbyte IConvertible.ToSByte(IFormatProvider provider) { 1313 throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "DateTime", "SByte")); 1314 } 1315 1316 /// <internalonly/> IConvertible.ToByteSystem.DateTime1317 byte IConvertible.ToByte(IFormatProvider provider) { 1318 throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "DateTime", "Byte")); 1319 } 1320 1321 /// <internalonly/> IConvertible.ToInt16System.DateTime1322 short IConvertible.ToInt16(IFormatProvider provider) { 1323 throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "DateTime", "Int16")); 1324 } 1325 1326 /// <internalonly/> IConvertible.ToUInt16System.DateTime1327 ushort IConvertible.ToUInt16(IFormatProvider provider) { 1328 throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "DateTime", "UInt16")); 1329 } 1330 1331 /// <internalonly/> IConvertible.ToInt32System.DateTime1332 int IConvertible.ToInt32(IFormatProvider provider) { 1333 throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "DateTime", "Int32")); 1334 } 1335 1336 /// <internalonly/> IConvertible.ToUInt32System.DateTime1337 uint IConvertible.ToUInt32(IFormatProvider provider) { 1338 throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "DateTime", "UInt32")); 1339 } 1340 1341 /// <internalonly/> IConvertible.ToInt64System.DateTime1342 long IConvertible.ToInt64(IFormatProvider provider) { 1343 throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "DateTime", "Int64")); 1344 } 1345 1346 /// <internalonly/> IConvertible.ToUInt64System.DateTime1347 ulong IConvertible.ToUInt64(IFormatProvider provider) { 1348 throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "DateTime", "UInt64")); 1349 } 1350 1351 /// <internalonly/> IConvertible.ToSingleSystem.DateTime1352 float IConvertible.ToSingle(IFormatProvider provider) { 1353 throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "DateTime", "Single")); 1354 } 1355 1356 /// <internalonly/> IConvertible.ToDoubleSystem.DateTime1357 double IConvertible.ToDouble(IFormatProvider provider) { 1358 throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "DateTime", "Double")); 1359 } 1360 1361 /// <internalonly/> IConvertible.ToDecimalSystem.DateTime1362 Decimal IConvertible.ToDecimal(IFormatProvider provider) { 1363 throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "DateTime", "Decimal")); 1364 } 1365 1366 /// <internalonly/> IConvertible.ToDateTimeSystem.DateTime1367 DateTime IConvertible.ToDateTime(IFormatProvider provider) { 1368 return this; 1369 } 1370 1371 /// <internalonly/> IConvertible.ToTypeSystem.DateTime1372 Object IConvertible.ToType(Type type, IFormatProvider provider) { 1373 return Convert.DefaultToType((IConvertible)this, type, provider); 1374 } 1375 1376 // Tries to construct a DateTime from a given year, month, day, hour, 1377 // minute, second and millisecond. 1378 // TryCreateSystem.DateTime1379 internal static Boolean TryCreate(int year, int month, int day, int hour, int minute, int second, int millisecond, out DateTime result) { 1380 result = DateTime.MinValue; 1381 if (year < 1 || year > 9999 || month < 1 || month > 12) { 1382 return false; 1383 } 1384 int[] days = IsLeapYear(year) ? DaysToMonth366 : DaysToMonth365; 1385 if (day < 1 || day > days[month] - days[month - 1]) { 1386 return false; 1387 } 1388 if (hour < 0 || hour >= 24 || minute < 0 || minute >= 60 || second < 0 || second >= 60) { 1389 return false; 1390 } 1391 if (millisecond < 0 || millisecond >= MillisPerSecond) { 1392 return false; 1393 } 1394 long ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second); 1395 1396 ticks += millisecond * TicksPerMillisecond; 1397 if (ticks < MinTicks || ticks > MaxTicks) { 1398 return false; 1399 } 1400 result = new DateTime(ticks, DateTimeKind.Unspecified); 1401 return true; 1402 } 1403 } 1404 } 1405