5 // Marcel Narings (marcel@narings.nl)
6 // Martin Baulig (martin@gnome.org)
7 // Atsushi Enomoto (atsushi@ximian.com)
9 // (C) 2001 Marcel Narings
10 // Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections;
33 using System.Globalization;
34 using System.Runtime.CompilerServices;
35 using System.Runtime.InteropServices;
41 /// The DateTime structure represents dates and time ranging from
42 /// 1-1-0001 12:00:00 AM to 31-12-9999 23:59:00 Common Era.
46 [StructLayout (LayoutKind.Auto)]
48 [System.Runtime.InteropServices.ComVisible (true)]
50 public struct DateTime : IFormattable, IConvertible, IComparable
52 , IComparable<DateTime>, IEquatable <DateTime>
55 private TimeSpan ticks;
61 private const int dp400 = 146097;
62 private const int dp100 = 36524;
63 private const int dp4 = 1461;
65 // w32 file time starts counting from 1/1/1601 00:00 GMT
66 // which is the constant ticks from the .NET epoch
67 private const long w32file_epoch = 504911232000000000L;
69 //private const long MAX_VALUE_TICKS = 3155378975400000000L;
70 // -- Microsoft .NET has this value.
71 private const long MAX_VALUE_TICKS = 3155378975999999999L;
74 // The UnixEpoch, it begins on Jan 1, 1970 at 0:0:0, expressed
77 internal const long UnixEpoch = 621355968000000000L;
79 // for OLE Automation dates
80 private const long ticks18991230 = 599264352000000000L;
81 private const double OAMinValue = -657435.0d;
82 private const double OAMaxValue = 2958466.0d;
84 public static readonly DateTime MaxValue = new DateTime (false, new TimeSpan (MAX_VALUE_TICKS));
85 public static readonly DateTime MinValue = new DateTime (false, new TimeSpan (0));
87 private static readonly string[] commonFormats = {
88 // For compatibility with MS's CLR, this format (which
89 // doesn't have a one-letter equivalent) is parsed
90 // too. It's important because it's used in XML
93 // Note that those format should be tried only for
96 // FIXME: SOME OF those patterns looks tried against
97 // the current culture, since some patterns fail in
101 "yyyy-MM-ddTHH:mm:sszzz",
102 "yyyy-MM-ddTHH:mm:ss.fffffff",
103 "yyyy-MM-ddTHH:mm:ss.fffffffzzz",
105 "yyyy-M-d H:m:s.fffffff",
106 // UTC / allow any separator
107 "yyyy/MM/ddTHH:mm:ssZ",
112 "yyyy/MM/dd HH:mm:ss 'GMT'",
115 // Close to RFC1123, but without 'GMT'
116 "ddd, d MMM yyyy HH:mm:ss",
117 // use UTC ('Z'; not literal "'Z'")
118 // FIXME: 1078(af-ZA) and 1079(ka-GE) reject it
119 "yyyy/MM/dd HH':'mm':'ssZ",
122 "M/d/yyyy HH':'mm':'ss tt",
124 // another funky COM dependent one
127 // DayOfTheWeek, dd full_month_name yyyy
128 // FIXME: 1054(th-TH) rejects them
129 "dddd, dd MMMM yyyy",
130 "dddd, dd MMMM yyyy HH:mm",
131 "dddd, dd MMMM yyyy HH:mm:ss",
134 // DayOfTheWeek, dd yyyy. This works for every locales.
137 // X509Certificate pattern is accepted by Parse() *in every culture*
140 // In Parse() the 'r' equivalent pattern is first parsed as universal time
141 "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'",
143 // Additionally there seems language-specific format
144 // patterns that however works in all language
146 // For example, the pattern below is for Japanese.
147 "yyyy'\u5E74'MM'\u6708'dd'\u65E5' HH'\u6642'mm'\u5206'ss'\u79D2'",
149 // This one is parsed for all cultures
150 "HH':'mm tt MM/dd/yyyy",
153 // Full date and time
154 "F", "G", "r", "s", "u", "U",
155 // Full date and time, but no seconds
161 // Only date, but no year
163 // Only date, but no day
176 private static readonly int[] daysmonth = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
177 private static readonly int[] daysmonthleap = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
179 private static int AbsoluteDays (int year, int month, int day)
184 days = (IsLeapYear(year) ? daysmonthleap : daysmonth);
188 return ((day-1) + temp + (365* (year-1)) + ((year-1)/4) - ((year-1)/100) + ((year-1)/400));
191 private int FromTicks(Which what)
193 int num400, num100, num4, numyears;
196 int[] days = daysmonth;
197 int totaldays = this.ticks.Days;
199 num400 = (totaldays / dp400);
200 totaldays -= num400 * dp400;
202 num100 = (totaldays / dp100);
203 if (num100 == 4) // leap
205 totaldays -= (num100 * dp100);
207 num4 = totaldays / dp4;
208 totaldays -= (num4 * dp4);
210 numyears = totaldays / 365 ;
212 if (numyears == 4) //leap
214 if (what == Which.Year )
215 return num400*400 + num100*100 + num4*4 + numyears + 1;
217 totaldays -= (numyears * 365) ;
218 if (what == Which.DayYear )
219 return totaldays + 1;
221 if ((numyears==3) && ((num100 == 3) || !(num4 == 24)) ) //31 dec leapyear
222 days = daysmonthleap;
224 while (totaldays >= days[M])
225 totaldays -= days[M++];
227 if (what == Which.Month )
237 /// Constructs a DateTime for specified ticks
240 public DateTime (long ticks)
242 this.ticks = new TimeSpan (ticks);
243 if (ticks < MinValue.Ticks || ticks > MaxValue.Ticks) {
244 string msg = Locale.GetText ("Value {0} is outside the valid range [{1},{2}].",
245 ticks, MinValue.Ticks, MaxValue.Ticks);
246 throw new ArgumentOutOfRangeException ("ticks", msg);
249 kind = DateTimeKind.Unspecified;
253 public DateTime (int year, int month, int day)
254 : this (year, month, day,0,0,0,0) {}
256 public DateTime (int year, int month, int day, int hour, int minute, int second)
257 : this (year, month, day, hour, minute, second, 0) {}
259 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond)
261 if ( year < 1 || year > 9999 ||
262 month < 1 || month >12 ||
263 day < 1 || day > DaysInMonth(year, month) ||
264 hour < 0 || hour > 23 ||
265 minute < 0 || minute > 59 ||
266 second < 0 || second > 59 ||
267 millisecond < 0 || millisecond > 999)
268 throw new ArgumentOutOfRangeException ("Parameters describe an " +
269 "unrepresentable DateTime.");
271 ticks = new TimeSpan (AbsoluteDays(year,month,day), hour, minute, second, millisecond);
274 kind = DateTimeKind.Unspecified;
278 [MonoTODO ("The Calendar is not taken into consideration")]
279 public DateTime (int year, int month, int day, Calendar calendar)
280 : this (year, month, day, 0, 0, 0, 0, calendar)
284 [MonoTODO ("The Calendar is not taken into consideration")]
285 public DateTime (int year, int month, int day, int hour, int minute, int second, Calendar calendar)
286 : this (year, month, day, hour, minute, second, 0, calendar)
290 [MonoTODO ("The Calendar is not taken into consideration")]
291 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar)
292 : this (year, month, day, hour, minute, second, millisecond)
294 if (calendar == null)
295 throw new ArgumentNullException ("calendar");
298 internal DateTime (bool check, TimeSpan value)
300 if (check && (value.Ticks < MinValue.Ticks || value.Ticks > MaxValue.Ticks))
301 throw new ArgumentOutOfRangeException ();
306 kind = DateTimeKind.Unspecified;
311 public DateTime (long ticks, DateTimeKind kind) : this (ticks)
313 CheckDateTimeKind (kind);
317 public DateTime (int year, int month, int day, int hour, int minute, int second, DateTimeKind kind)
318 : this (year, month, day, hour, minute, second)
320 CheckDateTimeKind (kind);
324 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind)
325 : this (year, month, day, hour, minute, second, millisecond)
327 CheckDateTimeKind (kind);
331 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, DateTimeKind kind)
332 : this (year, month, day, hour, minute, second, millisecond, calendar)
334 CheckDateTimeKind (kind);
345 DateTime ret = new DateTime (Year, Month, Day);
357 return FromTicks(Which.Month);
366 return FromTicks(Which.Day);
370 public DayOfWeek DayOfWeek
374 return ( (DayOfWeek) ((ticks.Days+1) % 7) );
382 return FromTicks(Which.DayYear);
386 public TimeSpan TimeOfDay
390 return new TimeSpan(ticks.Ticks % TimeSpan.TicksPerDay );
407 return ticks.Minutes;
415 return ticks.Seconds;
419 public int Millisecond
423 return ticks.Milliseconds;
427 [MethodImplAttribute(MethodImplOptions.InternalCall)]
428 internal static extern long GetNow ();
431 // To reduce the time consumed by DateTime.Now, we keep
432 // the difference to map the system time into a local
433 // time into `to_local_time_span', we record the timestamp
434 // for this in `last_now'
436 static object to_local_time_span_object;
437 static long last_now;
439 public static DateTime Now
443 long now = GetNow ();
444 DateTime dt = new DateTime (now);
446 if ((now - last_now) > TimeSpan.TicksPerMinute){
447 to_local_time_span_object = TimeZone.CurrentTimeZone.GetLocalTimeDiff (dt);
452 // This is boxed, so we avoid locking.
453 DateTime ret = dt + (TimeSpan) to_local_time_span_object;
455 ret.kind = DateTimeKind.Local;
469 public static DateTime Today
473 DateTime today = new DateTime (now.Year, now.Month, now.Day);
475 today.kind = now.kind;
481 public static DateTime UtcNow
485 return new DateTime (GetNow (), DateTimeKind.Utc);
487 return new DateTime (GetNow ());
496 return FromTicks(Which.Year);
501 public DateTimeKind Kind {
510 public DateTime Add (TimeSpan ts)
512 DateTime ret = AddTicks (ts.Ticks);
519 public DateTime AddDays (double days)
521 return AddMilliseconds (Math.Round (days * 86400000));
524 public DateTime AddTicks (long t)
526 if ((t + ticks.Ticks) > MAX_VALUE_TICKS || (t + ticks.Ticks) < 0) {
527 throw new ArgumentOutOfRangeException();
529 DateTime ret = new DateTime (t + ticks.Ticks);
536 public DateTime AddHours (double hours)
538 return AddMilliseconds (hours * 3600000);
541 public DateTime AddMilliseconds (double ms)
543 if ((ms * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
544 (ms * TimeSpan.TicksPerMillisecond) < long.MinValue) {
545 throw new ArgumentOutOfRangeException();
547 long msticks = (long) (ms * TimeSpan.TicksPerMillisecond);
549 return AddTicks (msticks);
552 // required to match MS implementation for OADate (OLE Automation)
553 private DateTime AddRoundedMilliseconds (double ms)
555 if ((ms * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
556 (ms * TimeSpan.TicksPerMillisecond) < long.MinValue) {
557 throw new ArgumentOutOfRangeException ();
559 long msticks = (long) (ms += ms > 0 ? 0.5 : -0.5) * TimeSpan.TicksPerMillisecond;
561 return AddTicks (msticks);
564 public DateTime AddMinutes (double minutes)
566 return AddMilliseconds (minutes * 60000);
569 public DateTime AddMonths (int months)
571 int day, month, year, maxday ;
575 month = this.Month + (months % 12);
576 year = this.Year + months/12 ;
588 maxday = DaysInMonth(year, month);
592 temp = new DateTime (year, month, day);
596 return temp.Add (this.TimeOfDay);
599 public DateTime AddSeconds (double seconds)
601 return AddMilliseconds (seconds*1000);
604 public DateTime AddYears (int years )
606 return AddMonths(years * 12);
609 public static int Compare (DateTime t1, DateTime t2)
611 if (t1.ticks < t2.ticks)
613 else if (t1.ticks > t2.ticks)
619 public int CompareTo (object v)
624 if (!(v is System.DateTime))
625 throw new ArgumentException (Locale.GetText (
626 "Value is not a System.DateTime"));
628 return Compare (this, (DateTime) v);
632 public bool IsDaylightSavingTime ()
634 if (kind == DateTimeKind.Utc)
636 return TimeZone.CurrentTimeZone.IsDaylightSavingTime (this);
639 public int CompareTo (DateTime value)
641 return Compare (this, value);
644 public bool Equals (DateTime value)
646 return value.ticks == ticks;
649 public long ToBinary ()
652 case DateTimeKind.Utc:
653 return Ticks | 0x4000000000000000;
654 case DateTimeKind.Local:
655 return (long) ((ulong)Ticks | 0x8000000000000000);
661 public static DateTime FromBinary (long dateData)
663 switch ((ulong)dateData >> 62) {
665 return new DateTime (dateData ^ 0x4000000000000000, DateTimeKind.Utc);
667 return new DateTime (dateData, DateTimeKind.Unspecified);
669 return new DateTime (((dateData << 2) >> 2), DateTimeKind.Local);
673 public static DateTime SpecifyKind (DateTime value, DateTimeKind kind)
675 return new DateTime (value.Ticks, kind);
679 public static int DaysInMonth (int year, int month)
683 if (month < 1 || month >12)
684 throw new ArgumentOutOfRangeException ();
686 days = (IsLeapYear(year) ? daysmonthleap : daysmonth);
690 public override bool Equals (object o)
692 if (!(o is System.DateTime))
695 return ((DateTime) o).ticks == ticks;
698 public static bool Equals (DateTime t1, DateTime t2 )
700 return (t1.ticks == t2.ticks );
703 public static DateTime FromFileTime (long fileTime)
706 throw new ArgumentOutOfRangeException ("fileTime", "< 0");
708 return new DateTime (w32file_epoch + fileTime).ToLocalTime ();
712 public static DateTime FromFileTimeUtc (long fileTime)
715 throw new ArgumentOutOfRangeException ("fileTime", "< 0");
717 return new DateTime (w32file_epoch + fileTime);
721 public static DateTime FromOADate (double d)
723 // An OLE Automation date is implemented as a floating-point number
724 // whose value is the number of days from midnight, 30 December 1899.
726 // d must be negative 657435.0 through positive 2958466.0.
727 if ((d <= OAMinValue) || (d >= OAMaxValue))
728 throw new ArgumentException ("d", "[-657435,2958466]");
730 DateTime dt = new DateTime (ticks18991230);
732 Double days = Math.Ceiling (d);
733 // integer part is the number of days (negative)
734 dt = dt.AddRoundedMilliseconds (days * 86400000);
735 // but decimals are the number of hours (in days fractions) and positive
736 Double hours = (days - d);
737 dt = dt.AddRoundedMilliseconds (hours * 86400000);
740 dt = dt.AddRoundedMilliseconds (d * 86400000);
746 public string[] GetDateTimeFormats()
748 return GetDateTimeFormats (CultureInfo.CurrentCulture);
751 public string[] GetDateTimeFormats(char format)
753 if ("dDgGfFmMrRstTuUyY".IndexOf (format) < 0)
754 throw new FormatException ("Invalid format character.");
755 string[] result = new string[1];
756 result[0] = this.ToString(format.ToString());
760 public string[] GetDateTimeFormats(IFormatProvider provider)
762 DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
763 // return GetDateTimeFormats (info.GetAllDateTimePatterns ());
764 ArrayList al = new ArrayList ();
765 foreach (char c in "dDgGfFmMrRstTuUyY")
766 al.AddRange (GetDateTimeFormats (c, info));
767 return al.ToArray (typeof (string)) as string [];
770 public string[] GetDateTimeFormats(char format,IFormatProvider provider )
772 if ("dDgGfFmMrRstTuUyY".IndexOf (format) < 0)
773 throw new FormatException ("Invalid format character.");
775 // LAMESPEC: There is NO assurance that 'U' ALWAYS
776 // euqals to 'F', but since we have to iterate all
777 // the pattern strings, we cannot just use
778 // ToString("U", provider) here. I believe that the
779 // method's behavior cannot be formalized.
780 bool adjustutc = false;
789 DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
790 return GetDateTimeFormats (adjustutc, info.GetAllRawDateTimePatterns (format), info);
793 private string [] GetDateTimeFormats (bool adjustutc, string [] patterns, DateTimeFormatInfo dfi)
795 string [] results = new string [patterns.Length];
796 DateTime val = adjustutc ? ToUniversalTime () : this;
797 for (int i = 0; i < results.Length; i++)
798 results [i] = val._ToString (patterns [i], dfi);
803 private void CheckDateTimeKind (DateTimeKind kind) {
804 if ((kind != DateTimeKind.Unspecified) && (kind != DateTimeKind.Utc) && (kind != DateTimeKind.Local))
805 throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
809 public override int GetHashCode ()
811 return (int) ticks.Ticks;
814 public TypeCode GetTypeCode ()
816 return TypeCode.DateTime;
819 public static bool IsLeapYear (int year)
821 return ( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ;
824 public static DateTime Parse (string s)
826 return Parse (s, null);
829 public static DateTime Parse (string s, IFormatProvider fp)
831 return Parse (s, fp, DateTimeStyles.AllowWhiteSpaces);
834 public static DateTime Parse (string s, IFormatProvider fp, DateTimeStyles styles)
836 // This method should try only expected patterns.
837 // Should not try extra patterns.
838 // Right now we also try InvariantCulture, but I
839 // confirmed in some cases this method rejects what
840 // InvariantCulture supports (can be checked against
841 // "th-TH" with Gregorian Calendar). So basically it
842 // should not be done.
843 // I think it should be CurrentCulture to be tested,
844 // but right now we don't support all the supported
845 // patterns for each culture, so try InvariantCulture
846 // as a quick remedy.
848 const string formatExceptionMessage = "String was not recognized as a valid DateTime.";
849 const string argumentYearRangeExceptionMessage = "Valid values are between 1 and 9999, inclusive.";
852 throw new ArgumentNullException (Locale.GetText ("s is null"));
856 fp = CultureInfo.CurrentCulture;
857 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (fp);
859 bool longYear = false;
861 // Try all the patterns
862 if (ParseExact (s, dfi.GetAllDateTimePatternsInternal (), dfi, styles, out result, false, ref longYear))
865 // Try common formats.
866 // if (ParseExact (s, commonFormats, dfi, styles, out result, false, ref longYear))
869 // Try common formats with invariant culture
870 if (ParseExact (s, commonFormats, DateTimeFormatInfo.InvariantInfo, styles, out result, false, ref longYear))
874 // .NET does not throw an ArgumentOutOfRangeException, but .NET 1.1 does.
875 throw new FormatException (formatExceptionMessage);
878 throw new ArgumentOutOfRangeException ("year",
879 argumentYearRangeExceptionMessage);
882 throw new FormatException (formatExceptionMessage);
886 public static DateTime ParseExact (string s, string format, IFormatProvider fp)
888 return ParseExact (s, format, fp, DateTimeStyles.None);
891 internal static int _ParseNumber (string s, int valuePos,
905 for (i = valuePos; i < s.Length && i < digits + valuePos; i++) {
906 if (!Char.IsDigit (s[i]))
912 digits = real_digits;
914 if (digits < min_digits) {
919 if (s.Length - valuePos < digits) {
924 for (i = valuePos; i < digits + valuePos; i++) {
926 if (!Char.IsDigit (c)) {
931 number = number * 10 + (byte) (c - '0');
938 internal static int _ParseEnum (string s, int sPos, string[] values, out int num_parsed)
942 // FIXME: I know this is somehow lame code. Probably
943 // it should iterate all the enum value and return
944 // the longest match. However right now I don't see
945 // anything but "1" and "10" - "12" that might match
946 // two or more values. (They are only abbrev month
947 // names, so do reverse order search). See bug #80094.
948 for (i = values.Length - 1; i >= 0; i--) {
949 if (s.Length - sPos < values[i].Length)
951 else if (values [i].Length == 0)
953 String tmp = s.Substring (sPos, values[i].Length);
954 if (String.Compare (tmp, values[i], true) == 0) {
955 num_parsed = values[i].Length;
964 internal static bool _ParseString (string s, int sPos, int maxlength, string value, out int num_parsed)
967 maxlength = value.Length;
969 if (String.Compare (s, sPos, value, 0, maxlength, true, CultureInfo.InvariantCulture) == 0) {
970 num_parsed = maxlength;
978 private static bool _DoParse (string s, string format, bool exact,
980 DateTimeFormatInfo dfi,
981 DateTimeStyles style,
985 DateTimeKind explicit_kind = DateTimeKind.Unspecified;
987 bool useutc = false, use_localtime = true;
988 bool use_invariant = false;
989 bool sloppy_parsing = false;
991 if (format.Length == 1)
992 format = _GetStandardPattern (format [0], dfi, out useutc, out use_invariant);
993 else if (!exact && CultureInfo.InvariantCulture.CompareInfo.IndexOf (format, "GMT", CompareOptions.Ordinal) >= 0)
996 if ((style & DateTimeStyles.AllowLeadingWhite) != 0) {
997 format = format.TrimStart (null);
999 s = s.TrimStart (null); // it could be optimized, but will make little good.
1002 if ((style & DateTimeStyles.AllowTrailingWhite) != 0) {
1003 format = format.TrimEnd (null);
1004 s = s.TrimEnd (null); // it could be optimized, but will make little good.
1008 dfi = DateTimeFormatInfo.InvariantInfo;
1010 if ((style & DateTimeStyles.AllowInnerWhite) != 0)
1011 sloppy_parsing = true;
1013 string chars = format;
1014 int len = format.Length, pos = 0, num = 0;
1016 int day = -1, dayofweek = -1, month = -1, year = -1;
1017 int hour = -1, minute = -1, second = -1;
1018 double fractionalSeconds = -1;
1020 int tzsign = -1, tzoffset = -1, tzoffmin = -1;
1022 result = new DateTime (0);
1023 while (pos+num < len)
1025 if (s.Length == valuePos)
1028 bool leading_zeros = true;
1030 if (chars[pos] == '\'') {
1032 while (pos+num < len) {
1033 if (chars[pos+num] == '\'')
1036 if (valuePos == s.Length)
1038 if (s [valuePos] != chars [pos + num])
1050 } else if (chars[pos] == '"') {
1052 while (pos+num < len) {
1053 if (chars[pos+num] == '"')
1056 if (valuePos == s.Length)
1058 if (s [valuePos] != chars[pos+num])
1070 } else if (chars[pos] == '\\') {
1076 if (s [valuePos] != chars [pos])
1081 } else if (chars[pos] == '%') {
1084 } else if (Char.IsWhiteSpace (s [valuePos]) ||
1085 s [valuePos] == ',' && Char.IsWhiteSpace (chars [pos])) {
1088 if (exact && (style & DateTimeStyles.AllowInnerWhite) == 0) {
1089 if (!Char.IsWhiteSpace (chars[pos]))
1096 while (ws < s.Length) {
1097 if (Char.IsWhiteSpace (s [ws]) || s [ws] == ',')
1104 while (ws < chars.Length) {
1105 if (Char.IsWhiteSpace (chars [ws]) || chars [ws] == ',')
1114 if ((pos+num+1 < len) && (chars[pos+num+1] == chars[pos+num])) {
1128 day = _ParseNumber (s, valuePos,0, 2, false, sloppy_parsing, out num_parsed);
1130 day = _ParseNumber (s, valuePos,0, 2, true, sloppy_parsing, out num_parsed);
1132 dayofweek = _ParseEnum (s, valuePos, dfi.RawAbbreviatedDayNames, out num_parsed);
1135 dayofweek = _ParseEnum (s, valuePos, dfi.RawDayNames, out num_parsed);
1143 month = _ParseNumber (s, valuePos, 0, 2, false, sloppy_parsing, out num_parsed);
1145 month = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1147 month = _ParseEnum (s, valuePos, dfi.RawAbbreviatedMonthNames , out num_parsed) + 1;
1150 month = _ParseEnum (s, valuePos, dfi.RawMonthNames, out num_parsed) + 1;
1159 year = _ParseNumber (s, valuePos,0, 2, false, sloppy_parsing, out num_parsed);
1160 } else if (num < 3) {
1161 year = _ParseNumber (s, valuePos,0, 2, true, sloppy_parsing, out num_parsed);
1163 year = _ParseNumber (s, valuePos,4, 4, false, sloppy_parsing, out num_parsed);
1164 if ((year >= 1000) && (num_parsed == 4) && (!longYear) && (s.Length > 4 + valuePos)) {
1166 int ly = _ParseNumber (s, valuePos, 5, 5, false, sloppy_parsing, out np);
1167 longYear = (ly > 9999);
1172 //FIXME: We should do use dfi.Calendat.TwoDigitYearMax
1173 if (num_parsed <= 2)
1174 year += (year < 30) ? 2000 : 1900;
1180 hour = _ParseNumber (s, valuePos,0, 2, false, sloppy_parsing, out num_parsed);
1183 hour = _ParseNumber (s, valuePos,0, 2, true, sloppy_parsing, out num_parsed);
1194 if ((hour != -1) || (ampm >= 0))
1197 hour = _ParseNumber (s, valuePos,0, 2, false, sloppy_parsing, out num_parsed);
1200 hour = _ParseNumber (s, valuePos,0, 2, true, sloppy_parsing, out num_parsed);
1212 minute = _ParseNumber (s, valuePos, 0, 2, false, sloppy_parsing, out num_parsed);
1215 minute = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1226 second = _ParseNumber (s, valuePos, 0, 2, false, sloppy_parsing, out num_parsed);
1229 second = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1238 leading_zeros = false;
1242 if (fractionalSeconds != -1)
1244 num = Math.Min (num, 6);
1245 double decimalNumber = (double) _ParseNumber (s, valuePos, 0, num+1, leading_zeros, sloppy_parsing, out num_parsed);
1246 if (num_parsed == -1)
1250 fractionalSeconds = decimalNumber / Math.Pow(10.0, num_parsed);
1257 if (_ParseString (s, valuePos, 1, dfi.AMDesignator, out num_parsed))
1259 else if (_ParseString (s, valuePos, 1, dfi.PMDesignator, out num_parsed))
1266 if (_ParseString (s, valuePos, 0, dfi.AMDesignator, out num_parsed))
1268 else if (_ParseString (s, valuePos, 0, dfi.PMDesignator, out num_parsed))
1278 if (s [valuePos] == '+')
1280 else if (s [valuePos] == '-')
1286 tzoffset = _ParseNumber (s, valuePos, 0, 2, false, sloppy_parsing, out num_parsed);
1288 tzoffset = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1291 tzoffset = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1294 valuePos += num_parsed;
1295 if (Char.IsDigit (s [valuePos]))
1297 else if (!_ParseString (s, valuePos, 0, dfi.TimeSeparator, out num_parsed))
1299 valuePos += num_parsed;
1300 tzoffmin = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1308 if (s [valuePos] == 'Z') {
1310 explicit_kind = DateTimeKind.Utc;
1311 } else if (s [valuePos] == '+' || s [valuePos] == '-') {
1314 if (s [valuePos] == '+')
1316 else if (s [valuePos] == '-')
1321 tzoffset = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1324 valuePos += num_parsed;
1325 if (Char.IsDigit (s [valuePos]))
1327 else if (!_ParseString (s, valuePos, 0, dfi.TimeSeparator, out num_parsed))
1329 valuePos += num_parsed;
1330 tzoffmin = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1334 explicit_kind = DateTimeKind.Local;
1338 // LAMESPEC: This should be part of UTCpattern
1339 // string and thus should not be considered here.
1341 // Note that 'Z' is not defined as a pattern
1342 // character. Keep it for X509 certificate
1343 // verification. Also, "Z" != "'Z'" under MS.NET
1344 // ("'Z'" is just literal; handled above)
1346 if (s [valuePos] != 'Z')
1354 if (!_ParseString (s, valuePos, 0, dfi.TimeSeparator, out num_parsed))
1358 /* Accept any character for
1359 * DateSeparator, except
1360 * TimeSeparator, a digit or a
1361 * letter. Not documented,
1362 * but seems to be MS
1363 * behaviour here. See bug
1366 if (exact && s [valuePos] != '/')
1369 if (_ParseString (s, valuePos, 0,
1372 Char.IsDigit (s [valuePos]) ||
1373 Char.IsLetter (s [valuePos])) {
1378 if (num_parsed <= 0) {
1384 if (s [valuePos] != chars[pos]) {
1385 // FIXME: It is not sure, but
1386 // IsLetter() is introduced
1387 // because we have to reject
1388 // "2002a02b25" but have to
1389 // allow "2002$02$25". The same
1390 // thing applies to '/' case.
1392 Char.IsDigit (s [valuePos]) ||
1393 Char.IsLetter (s [valuePos]))
1404 valuePos += num_parsed;
1407 switch (chars [pos]) {
1415 if (s.Length > valuePos && s [valuePos] == 'Z'
1416 && (pos + 1 == chars.Length
1417 || chars [pos + 1] != 'Z')) {
1425 pos = pos + num + 1;
1429 // possible empty value. Regarded as no match.
1436 if (s.Length != valuePos) // extraneous tail.
1446 if (fractionalSeconds == -1)
1447 fractionalSeconds = 0;
1449 // If no date was given
1450 if ((day == -1) && (month == -1) && (year == -1)) {
1451 if ((style & DateTimeStyles.NoCurrentDateDefault) != 0) {
1457 month = Today.Month;
1468 if ((style & DateTimeStyles.NoCurrentDateDefault) != 0)
1477 // For anything out of range
1479 if ( year < 1 || year > 9999 ||
1480 month < 1 || month >12 ||
1481 day < 1 || day > DaysInMonth(year, month) ||
1482 hour < 0 || hour > 23 ||
1483 minute < 0 || minute > 59 ||
1484 second < 0 || second > 59 )
1487 result = new DateTime (year, month, day, hour, minute, second, 0);
1488 result = result.AddSeconds(fractionalSeconds);
1490 if ((dayofweek != -1) && (dayofweek != (int) result.DayOfWeek))
1491 throw new FormatException (Locale.GetText ("String was not recognized as valid DateTime because the day of week was incorrect."));
1493 // If no timezone was specified, default to the local timezone.
1497 if ((style & DateTimeStyles.AdjustToUniversal) != 0)
1498 use_localtime = false;
1499 utcoffset = new TimeSpan (0, 0, 0);
1500 } else if (tzsign == -1) {
1501 TimeZone tz = TimeZone.CurrentTimeZone;
1502 utcoffset = tz.GetUtcOffset (result);
1504 if ((style & DateTimeStyles.AdjustToUniversal) != 0)
1505 use_localtime = false;
1512 tzoffset = -tzoffset;
1514 utcoffset = new TimeSpan (tzoffset, tzoffmin, 0);
1517 long newticks = (result.ticks - utcoffset).Ticks;
1519 result = new DateTime (false, new TimeSpan (newticks));
1521 if (explicit_kind != DateTimeKind.Unspecified)
1522 result.kind = explicit_kind;
1523 else if (use_localtime)
1524 result = result.ToLocalTime ();
1526 result.kind = DateTimeKind.Utc;
1529 result = result.ToLocalTime ();
1536 public static DateTime ParseExact (string s, string format,
1537 IFormatProvider fp, DateTimeStyles style)
1540 throw new ArgumentNullException ("format");
1542 string [] formats = new string [1];
1543 formats[0] = format;
1545 return ParseExact (s, formats, fp, style);
1548 public static DateTime ParseExact (string s, string[] formats,
1550 DateTimeStyles style)
1552 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (fp);
1555 throw new ArgumentNullException ("s");
1556 if (formats == null)
1557 throw new ArgumentNullException ("formats");
1558 if (formats.Length == 0)
1559 throw new FormatException ("Format specifier was invalid.");
1561 for (int i = 0; i < formats.Length; i++) {
1562 string format = formats [i];
1563 if (format == null || format.Length == 0)
1564 throw new FormatException ("Format specifier was invalid.");
1568 bool longYear = false;
1569 if (!ParseExact (s, formats, dfi, style, out result, true, ref longYear))
1570 throw new FormatException ();
1575 public static bool TryParse (string s, out DateTime result)
1586 public static bool TryParse (string s, IFormatProvider provider, DateTimeStyles styles, out DateTime result)
1589 result = Parse (s, provider, styles);
1597 public static bool TryParseExact (string s, string format,
1599 DateTimeStyles style,
1600 out DateTime result)
1604 formats = new string [1];
1605 formats[0] = format;
1607 return TryParseExact (s, formats, fp, style, out result);
1610 public static bool TryParseExact (string s, string[] formats,
1612 DateTimeStyles style,
1613 out DateTime result)
1615 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (fp);
1617 bool longYear = false;
1618 return ParseExact (s, formats, dfi, style, out result, true, ref longYear);
1622 private static bool ParseExact (string s, string [] formats,
1623 DateTimeFormatInfo dfi, DateTimeStyles style, out DateTime ret,
1624 bool exact, ref bool longYear)
1627 for (i = 0; i < formats.Length; i++)
1631 if (_DoParse (s, formats[i], exact, out result, dfi, style, ref longYear)) {
1636 ret = DateTime.MinValue;
1640 public TimeSpan Subtract(DateTime dt)
1642 return new TimeSpan(ticks.Ticks) - dt.ticks;
1645 public DateTime Subtract(TimeSpan ts)
1649 newticks = (new TimeSpan (ticks.Ticks)) - ts;
1650 DateTime ret = new DateTime(true,newticks);
1657 public long ToFileTime()
1659 DateTime universalTime = ToUniversalTime();
1661 if (universalTime.Ticks < w32file_epoch) {
1662 throw new ArgumentOutOfRangeException("file time is not valid");
1665 return(universalTime.Ticks - w32file_epoch);
1669 public long ToFileTimeUtc()
1671 if (Ticks < w32file_epoch) {
1672 throw new ArgumentOutOfRangeException("file time is not valid");
1675 return (Ticks - w32file_epoch);
1679 public string ToLongDateString()
1681 return ToString ("D");
1684 public string ToLongTimeString()
1686 return ToString ("T");
1689 public double ToOADate ()
1691 long t = this.Ticks;
1692 // uninitialized DateTime case
1695 // we can't reach minimum value
1696 if (t < 31242239136000000)
1697 return OAMinValue + 0.001;
1699 TimeSpan ts = new TimeSpan (this.Ticks - ticks18991230);
1700 double result = ts.TotalDays;
1701 // t < 0 (where 599264352000000000 == 0.0d for OA)
1702 if (t < 599264352000000000) {
1703 // negative days (int) but decimals are positive
1704 double d = Math.Ceiling (result);
1705 result = d - 2 - (result - d);
1708 // we can't reach maximum value
1709 if (result >= OAMaxValue)
1710 result = OAMaxValue - 0.00000001d;
1715 public string ToShortDateString()
1717 return ToString ("d");
1720 public string ToShortTimeString()
1722 return ToString ("t");
1725 public override string ToString ()
1727 return ToString ("G", null);
1730 public string ToString (IFormatProvider fp)
1732 return ToString (null, fp);
1735 public string ToString (string format)
1737 return ToString (format, null);
1740 internal static string _GetStandardPattern (char format, DateTimeFormatInfo dfi, out bool useutc, out bool use_invariant)
1745 use_invariant = false;
1750 pattern = dfi.ShortDatePattern;
1753 pattern = dfi.LongDatePattern;
1756 pattern = dfi.LongDatePattern + " " + dfi.ShortTimePattern;
1759 pattern = dfi.FullDateTimePattern;
1762 pattern = dfi.ShortDatePattern + " " + dfi.ShortTimePattern;
1765 pattern = dfi.ShortDatePattern + " " + dfi.LongTimePattern;
1769 pattern = dfi.MonthDayPattern;
1773 pattern = dfi.RoundtripPattern;
1778 pattern = dfi.RFC1123Pattern;
1779 // commented by LP 09/jun/2002, rfc 1123 pattern is always in GMT
1780 // uncommented by AE 27/may/2004
1782 use_invariant = true;
1785 pattern = dfi.SortableDateTimePattern;
1788 pattern = dfi.ShortTimePattern;
1791 pattern = dfi.LongTimePattern;
1794 pattern = dfi.UniversalSortableDateTimePattern;
1798 // pattern = dfi.LongDatePattern + " " + dfi.LongTimePattern;
1799 pattern = dfi.FullDateTimePattern;
1804 pattern = dfi.YearMonthPattern;
1809 // throw new FormatException (String.Format ("Invalid format pattern: '{0}'", format));
1815 internal string _ToString (string format, DateTimeFormatInfo dfi)
1817 // the length of the format is usually a good guess of the number
1818 // of chars in the result. Might save us a few bytes sometimes
1819 // Add + 10 for cases like mmmm dddd
1820 StringBuilder result = new StringBuilder (format.Length + 10);
1822 // For some cases, the output should not use culture dependent calendar
1823 DateTimeFormatInfo inv = DateTimeFormatInfo.InvariantInfo;
1824 if (format == inv.RFC1123Pattern)
1826 else if (format == inv.UniversalSortableDateTimePattern)
1831 while (i < format.Length) {
1833 bool omitZeros = false;
1834 char ch = format [i];
1843 tokLen = CountRepeat (format, i, ch);
1845 int hr = this.Hour % 12;
1849 ZeroPad (result, hr, tokLen == 1 ? 1 : 2);
1853 tokLen = CountRepeat (format, i, ch);
1854 ZeroPad (result, this.Hour, tokLen == 1 ? 1 : 2);
1858 tokLen = CountRepeat (format, i, ch);
1859 ZeroPad (result, this.Minute, tokLen == 1 ? 1 : 2);
1863 tokLen = CountRepeat (format, i, ch);
1864 ZeroPad (result, this.Second, tokLen == 1 ? 1 : 2);
1872 // fraction of second, to same number of
1873 // digits as there are f's
1875 tokLen = CountRepeat (format, i, ch);
1877 throw new FormatException ("Invalid Format String");
1879 int dec = (int)((long)(this.Ticks % TimeSpan.TicksPerSecond) / (long) Math.Pow (10, 7 - tokLen));
1880 int startLen = result.Length;
1881 ZeroPad (result, dec, tokLen);
1884 while (result.Length > startLen && result [result.Length - 1] == '0')
1886 // when the value was 0, then trim even preceding '.' (!) It is fixed character.
1887 if (dec == 0 && startLen > 0 && result [startLen - 1] == '.')
1893 // AM/PM. t == first char, tt+ == full
1894 tokLen = CountRepeat (format, i, ch);
1895 string desig = this.Hour < 12 ? dfi.AMDesignator : dfi.PMDesignator;
1898 if (desig.Length >= 1)
1899 result.Append (desig [0]);
1902 result.Append (desig);
1906 // timezone. t = +/-h; tt = +/-hh; ttt+=+/-hh:mm
1907 tokLen = CountRepeat (format, i, ch);
1908 TimeSpan offset = TimeZone.CurrentTimeZone.GetUtcOffset (this);
1910 if (offset.Ticks >= 0)
1911 result.Append ('+');
1913 result.Append ('-');
1917 result.Append (Math.Abs (offset.Hours));
1920 result.Append (Math.Abs (offset.Hours).ToString ("00"));
1923 result.Append (Math.Abs (offset.Hours).ToString ("00"));
1924 result.Append (':');
1925 result.Append (Math.Abs (offset.Minutes).ToString ("00"));
1930 case 'K': // 'Z' (UTC) or zzz (Local)
1933 case DateTimeKind.Utc:
1934 result.Append ('Z');
1936 case DateTimeKind.Local:
1937 offset = TimeZone.CurrentTimeZone.GetUtcOffset (this);
1938 if (offset.Ticks >= 0)
1939 result.Append ('+');
1941 result.Append ('-');
1942 result.Append (Math.Abs (offset.Hours).ToString ("00"));
1943 result.Append (':');
1944 result.Append (Math.Abs (offset.Minutes).ToString ("00"));
1953 // day. d(d?) = day of month (leading 0 if two d's)
1954 // ddd = three leter day of week
1955 // dddd+ full day-of-week
1956 tokLen = CountRepeat (format, i, ch);
1959 ZeroPad (result, dfi.Calendar.GetDayOfMonth (this), tokLen == 1 ? 1 : 2);
1960 else if (tokLen == 3)
1961 result.Append (dfi.GetAbbreviatedDayName (dfi.Calendar.GetDayOfWeek (this)));
1963 result.Append (dfi.GetDayName (dfi.Calendar.GetDayOfWeek (this)));
1967 // Month.m(m?) = month # (with leading 0 if two mm)
1968 // mmm = 3 letter name
1969 // mmmm+ = full name
1970 tokLen = CountRepeat (format, i, ch);
1971 int month = dfi.Calendar.GetMonth(this);
1973 ZeroPad (result, month, tokLen);
1974 else if (tokLen == 3)
1975 result.Append (dfi.GetAbbreviatedMonthName (month));
1977 result.Append (dfi.GetMonthName (month));
1981 // Year. y(y?) = two digit year, with leading 0 if yy
1982 // yyy+ full year, if yyy and yr < 1000, displayed as three digits
1983 tokLen = CountRepeat (format, i, ch);
1986 ZeroPad (result, dfi.Calendar.GetYear (this) % 100, tokLen);
1988 ZeroPad (result, dfi.Calendar.GetYear (this), (tokLen == 3 ? 3 : 4));
1993 tokLen = CountRepeat (format, i, ch);
1994 result.Append (dfi.GetEraName (dfi.Calendar.GetEra (this)));
2001 result.Append (dfi.TimeSeparator);
2005 result.Append (dfi.DateSeparator);
2008 case '\'': case '"':
2009 tokLen = ParseQuotedString (format, i, result);
2012 if (i >= format.Length - 1)
2013 throw new FormatException ("% at end of date time string");
2014 if (format [i + 1] == '%')
2015 throw new FormatException ("%% in date string");
2017 // Look for the next char
2022 if (i >= format.Length - 1)
2023 throw new FormatException ("\\ at end of date time string");
2025 result.Append (format [i + 1]);
2037 return result.ToString ();
2040 static int CountRepeat (string fmt, int p, char c)
2044 while ((i < l) && (fmt [i] == c))
2050 static int ParseQuotedString (string fmt, int pos, StringBuilder output)
2052 // pos == position of " or '
2054 int len = fmt.Length;
2056 char quoteChar = fmt [pos++];
2059 char ch = fmt [pos++];
2061 if (ch == quoteChar)
2067 throw new FormatException("Un-ended quote");
2069 output.Append (fmt [pos++]);
2075 throw new FormatException("Un-ended quote");
2078 static unsafe void ZeroPad (StringBuilder output, int digits, int len)
2080 // more than enough for an int
2081 char* buffer = stackalloc char [16];
2085 buffer [-- pos] = (char) ('0' + digits % 10);
2088 } while (digits > 0);
2091 buffer [-- pos] = '0';
2093 output.Append (new string (buffer, pos, 16 - pos));
2096 public string ToString (string format, IFormatProvider fp)
2098 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance(fp);
2100 if (format == null || format == String.Empty)
2103 bool useutc = false, use_invariant = false;
2105 if (format.Length == 1) {
2106 char fchar = format [0];
2107 format = _GetStandardPattern (fchar, dfi, out useutc, out use_invariant);
2110 // Don't convert UTC value. It just adds 'Z' for
2111 // 'u' format, for the same ticks.
2112 return this._ToString (format, dfi);
2115 public DateTime ToLocalTime ()
2117 return TimeZone.CurrentTimeZone.ToLocalTime (this);
2120 public DateTime ToUniversalTime()
2122 return TimeZone.CurrentTimeZone.ToUniversalTime (this);
2127 public static DateTime operator +(DateTime d, TimeSpan t)
2129 DateTime ret = new DateTime (true, d.ticks + t);
2136 public static bool operator ==(DateTime d1, DateTime d2)
2138 return (d1.ticks == d2.ticks);
2141 public static bool operator >(DateTime t1,DateTime t2)
2143 return (t1.ticks > t2.ticks);
2146 public static bool operator >=(DateTime t1,DateTime t2)
2148 return (t1.ticks >= t2.ticks);
2151 public static bool operator !=(DateTime d1, DateTime d2)
2153 return (d1.ticks != d2.ticks);
2156 public static bool operator <(DateTime t1, DateTime t2)
2158 return (t1.ticks < t2.ticks );
2161 public static bool operator <=(DateTime t1,DateTime t2)
2163 return (t1.ticks <= t2.ticks);
2166 public static TimeSpan operator -(DateTime d1,DateTime d2)
2168 return new TimeSpan((d1.ticks - d2.ticks).Ticks);
2171 public static DateTime operator -(DateTime d,TimeSpan t)
2173 DateTime ret = new DateTime (true, d.ticks - t);
2180 bool IConvertible.ToBoolean(IFormatProvider provider)
2182 throw new InvalidCastException();
2185 byte IConvertible.ToByte(IFormatProvider provider)
2187 throw new InvalidCastException();
2191 char IConvertible.ToChar(IFormatProvider provider)
2193 throw new InvalidCastException();
2196 System.DateTime IConvertible.ToDateTime(IFormatProvider provider)
2201 decimal IConvertible.ToDecimal(IFormatProvider provider)
2203 throw new InvalidCastException();
2206 double IConvertible.ToDouble(IFormatProvider provider)
2208 throw new InvalidCastException();
2211 Int16 IConvertible.ToInt16(IFormatProvider provider)
2213 throw new InvalidCastException();
2216 Int32 IConvertible.ToInt32(IFormatProvider provider)
2218 throw new InvalidCastException();
2221 Int64 IConvertible.ToInt64(IFormatProvider provider)
2223 throw new InvalidCastException();
2226 SByte IConvertible.ToSByte(IFormatProvider provider)
2228 throw new InvalidCastException();
2231 Single IConvertible.ToSingle(IFormatProvider provider)
2233 throw new InvalidCastException();
2236 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
2238 if (conversionType == null)
2239 throw new ArgumentNullException ("conversionType");
2241 if (conversionType == typeof (DateTime))
2243 else if (conversionType == typeof (String))
2244 return this.ToString (provider);
2245 else if (conversionType == typeof (Object))
2248 throw new InvalidCastException();
2251 UInt16 IConvertible.ToUInt16(IFormatProvider provider)
2253 throw new InvalidCastException();
2256 UInt32 IConvertible.ToUInt32(IFormatProvider provider)
2258 throw new InvalidCastException();
2261 UInt64 IConvertible.ToUInt64(IFormatProvider provider)
2263 throw new InvalidCastException();