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)]
47 public struct DateTime : IFormattable, IConvertible, IComparable
49 , IComparable<DateTime>, IEquatable <DateTime>
52 private TimeSpan ticks;
58 private const int dp400 = 146097;
59 private const int dp100 = 36524;
60 private const int dp4 = 1461;
62 // w32 file time starts counting from 1/1/1601 00:00 GMT
63 // which is the constant ticks from the .NET epoch
64 private const long w32file_epoch = 504911232000000000L;
66 //private const long MAX_VALUE_TICKS = 3155378975400000000L;
67 // -- Microsoft .NET has this value.
68 private const long MAX_VALUE_TICKS = 3155378975999999999L;
71 // The UnixEpoch, it begins on Jan 1, 1970 at 0:0:0, expressed
74 internal const long UnixEpoch = 621355968000000000L;
76 // for OLE Automation dates
77 private const long ticks18991230 = 599264352000000000L;
78 private const double OAMinValue = -657435.0d;
79 private const double OAMaxValue = 2958466.0d;
81 public static readonly DateTime MaxValue = new DateTime (false, new TimeSpan (MAX_VALUE_TICKS));
82 public static readonly DateTime MinValue = new DateTime (false, new TimeSpan (0));
84 // DateTime.Parse patterns
85 // Patterns are divided to date and time patterns. The algorithm will
86 // try combinations of these patterns. The algorithm also looks for
87 // day of the week, AM/PM GMT and Z independently of the patterns.
88 private static readonly string[] ParseTimeFormats = new string [] {
95 "H tt", // Specifies AM to disallow '8'.
96 "H'\u6642'm'\u5206's'\u79D2'",
99 // DateTime.Parse date patterns extend ParseExact patterns as follows:
100 // MMM - month short name or month full name
101 // MMMM - month number or short name or month full name
103 // Parse behaves differently according to the ShorDatePattern of the
104 // DateTimeFormatInfo. The following define the date patterns for
105 // different orders of day, month and year in ShorDatePattern.
106 // Note that the year cannot go between the day and the month.
107 private static readonly string[] ParseYearDayMonthFormats = new string [] {
110 "yyyy'\u5E74'M'\u6708'd'\u65E5",
127 private static readonly string[] ParseYearMonthDayFormats = new string [] {
130 "yyyy'\u5E74'M'\u6708'd'\u65E5",
144 private static readonly string[] ParseDayMonthYearFormats = new string [] {
147 "yyyy'\u5E74'M'\u6708'd'\u65E5",
164 private static readonly string[] ParseMonthDayYearFormats = new string [] {
167 "yyyy'\u5E74'M'\u6708'd'\u65E5",
184 // Patterns influenced by the MonthDayPattern in DateTimeFormatInfo.
185 // Note that these patterns cannot be followed by the time.
186 private static readonly string[] MonthDayShortFormats = new string [] {
191 private static readonly string[] DayMonthShortFormats = new string [] {
195 #else // In .Net 1.0 Feb 03 is always Feb 3rd (and not Feb 2003)
209 private static readonly int[] daysmonth = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
210 private static readonly int[] daysmonthleap = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
212 private static int AbsoluteDays (int year, int month, int day)
217 days = (IsLeapYear(year) ? daysmonthleap : daysmonth);
221 return ((day-1) + temp + (365* (year-1)) + ((year-1)/4) - ((year-1)/100) + ((year-1)/400));
224 private int FromTicks(Which what)
226 int num400, num100, num4, numyears;
229 int[] days = daysmonth;
230 int totaldays = this.ticks.Days;
232 num400 = (totaldays / dp400);
233 totaldays -= num400 * dp400;
235 num100 = (totaldays / dp100);
236 if (num100 == 4) // leap
238 totaldays -= (num100 * dp100);
240 num4 = totaldays / dp4;
241 totaldays -= (num4 * dp4);
243 numyears = totaldays / 365 ;
245 if (numyears == 4) //leap
247 if (what == Which.Year )
248 return num400*400 + num100*100 + num4*4 + numyears + 1;
250 totaldays -= (numyears * 365) ;
251 if (what == Which.DayYear )
252 return totaldays + 1;
254 if ((numyears==3) && ((num100 == 3) || !(num4 == 24)) ) //31 dec leapyear
255 days = daysmonthleap;
257 while (totaldays >= days[M])
258 totaldays -= days[M++];
260 if (what == Which.Month )
270 /// Constructs a DateTime for specified ticks
273 public DateTime (long ticks)
275 this.ticks = new TimeSpan (ticks);
276 if (ticks < MinValue.Ticks || ticks > MaxValue.Ticks) {
277 string msg = Locale.GetText ("Value {0} is outside the valid range [{1},{2}].",
278 ticks, MinValue.Ticks, MaxValue.Ticks);
279 throw new ArgumentOutOfRangeException ("ticks", msg);
282 kind = DateTimeKind.Unspecified;
286 public DateTime (int year, int month, int day)
287 : this (year, month, day,0,0,0,0) {}
289 public DateTime (int year, int month, int day, int hour, int minute, int second)
290 : this (year, month, day, hour, minute, second, 0) {}
292 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond)
294 if ( year < 1 || year > 9999 ||
295 month < 1 || month >12 ||
296 day < 1 || day > DaysInMonth(year, month) ||
297 hour < 0 || hour > 23 ||
298 minute < 0 || minute > 59 ||
299 second < 0 || second > 59 ||
300 millisecond < 0 || millisecond > 999)
301 throw new ArgumentOutOfRangeException ("Parameters describe an " +
302 "unrepresentable DateTime.");
304 ticks = new TimeSpan (AbsoluteDays(year,month,day), hour, minute, second, millisecond);
307 kind = DateTimeKind.Unspecified;
311 public DateTime (int year, int month, int day, Calendar calendar)
312 : this (year, month, day, 0, 0, 0, 0, calendar)
316 public DateTime (int year, int month, int day, int hour, int minute, int second, Calendar calendar)
317 : this (year, month, day, hour, minute, second, 0, calendar)
321 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar)
323 if (calendar == null)
324 throw new ArgumentNullException ("calendar");
325 ticks = calendar.ToDateTime (year, month, day, hour, minute, second, millisecond).ticks;
327 kind = DateTimeKind.Unspecified;
331 internal DateTime (bool check, TimeSpan value)
333 if (check && (value.Ticks < MinValue.Ticks || value.Ticks > MaxValue.Ticks))
334 throw new ArgumentOutOfRangeException ();
339 kind = DateTimeKind.Unspecified;
344 public DateTime (long ticks, DateTimeKind kind) : this (ticks)
346 CheckDateTimeKind (kind);
350 public DateTime (int year, int month, int day, int hour, int minute, int second, DateTimeKind kind)
351 : this (year, month, day, hour, minute, second)
353 CheckDateTimeKind (kind);
357 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind)
358 : this (year, month, day, hour, minute, second, millisecond)
360 CheckDateTimeKind (kind);
364 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, DateTimeKind kind)
365 : this (year, month, day, hour, minute, second, millisecond, calendar)
367 CheckDateTimeKind (kind);
378 DateTime ret = new DateTime (Year, Month, Day);
390 return FromTicks(Which.Month);
398 return FromTicks(Which.Day);
402 public DayOfWeek DayOfWeek
406 return ( (DayOfWeek) ((ticks.Days+1) % 7) );
414 return FromTicks(Which.DayYear);
418 public TimeSpan TimeOfDay
422 return new TimeSpan(ticks.Ticks % TimeSpan.TicksPerDay );
439 return ticks.Minutes;
447 return ticks.Seconds;
451 public int Millisecond
455 return ticks.Milliseconds;
459 [MethodImplAttribute(MethodImplOptions.InternalCall)]
460 internal static extern long GetTimeMonotonic ();
462 [MethodImplAttribute(MethodImplOptions.InternalCall)]
463 internal static extern long GetNow ();
466 // To reduce the time consumed by DateTime.Now, we keep
467 // the difference to map the system time into a local
468 // time into `to_local_time_span', we record the timestamp
469 // for this in `last_now'
471 static object to_local_time_span_object;
472 static long last_now;
474 public static DateTime Now
478 long now = GetNow ();
479 DateTime dt = new DateTime (now);
481 if ((now - last_now) > TimeSpan.TicksPerMinute){
482 to_local_time_span_object = TimeZone.CurrentTimeZone.GetLocalTimeDiff (dt);
487 // This is boxed, so we avoid locking.
488 DateTime ret = dt + (TimeSpan) to_local_time_span_object;
490 ret.kind = DateTimeKind.Local;
504 public static DateTime Today
508 DateTime today = new DateTime (now.Year, now.Month, now.Day);
510 today.kind = now.kind;
516 public static DateTime UtcNow
520 return new DateTime (GetNow (), DateTimeKind.Utc);
522 return new DateTime (GetNow ());
531 return FromTicks(Which.Year);
536 public DateTimeKind Kind {
545 public DateTime Add (TimeSpan ts)
547 DateTime ret = AddTicks (ts.Ticks);
554 public DateTime AddDays (double days)
556 return AddMilliseconds (Math.Round (days * 86400000));
559 public DateTime AddTicks (long t)
561 if ((t + ticks.Ticks) > MAX_VALUE_TICKS || (t + ticks.Ticks) < 0) {
562 throw new ArgumentOutOfRangeException();
564 DateTime ret = new DateTime (t + ticks.Ticks);
571 public DateTime AddHours (double hours)
573 return AddMilliseconds (hours * 3600000);
576 public DateTime AddMilliseconds (double ms)
578 if ((ms * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
579 (ms * TimeSpan.TicksPerMillisecond) < long.MinValue) {
580 throw new ArgumentOutOfRangeException();
582 long msticks = (long) (ms * TimeSpan.TicksPerMillisecond);
584 return AddTicks (msticks);
587 // required to match MS implementation for OADate (OLE Automation)
588 private DateTime AddRoundedMilliseconds (double ms)
590 if ((ms * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
591 (ms * TimeSpan.TicksPerMillisecond) < long.MinValue) {
592 throw new ArgumentOutOfRangeException ();
594 long msticks = (long) (ms += ms > 0 ? 0.5 : -0.5) * TimeSpan.TicksPerMillisecond;
596 return AddTicks (msticks);
599 public DateTime AddMinutes (double minutes)
601 return AddMilliseconds (minutes * 60000);
604 public DateTime AddMonths (int months)
606 int day, month, year, maxday ;
610 month = this.Month + (months % 12);
611 year = this.Year + months/12 ;
623 maxday = DaysInMonth(year, month);
627 temp = new DateTime (year, month, day);
631 return temp.Add (this.TimeOfDay);
634 public DateTime AddSeconds (double seconds)
636 return AddMilliseconds (seconds*1000);
639 public DateTime AddYears (int years )
641 return AddMonths(years * 12);
644 public static int Compare (DateTime t1, DateTime t2)
646 if (t1.ticks < t2.ticks)
648 else if (t1.ticks > t2.ticks)
654 public int CompareTo (object v)
659 if (!(v is System.DateTime))
660 throw new ArgumentException (Locale.GetText (
661 "Value is not a System.DateTime"));
663 return Compare (this, (DateTime) v);
667 public bool IsDaylightSavingTime ()
669 if (kind == DateTimeKind.Utc)
671 return TimeZone.CurrentTimeZone.IsDaylightSavingTime (this);
674 public int CompareTo (DateTime value)
676 return Compare (this, value);
679 public bool Equals (DateTime value)
681 return value.ticks == ticks;
684 public long ToBinary ()
687 case DateTimeKind.Utc:
688 return Ticks | 0x4000000000000000;
689 case DateTimeKind.Local:
690 return (long) ((ulong) ToUniversalTime ().Ticks | 0x8000000000000000);
696 public static DateTime FromBinary (long dateData)
698 switch ((ulong)dateData >> 62) {
700 return new DateTime (dateData ^ 0x4000000000000000, DateTimeKind.Utc);
702 return new DateTime (dateData, DateTimeKind.Unspecified);
704 return new DateTime (dateData & 0x3fffffffffffffff, DateTimeKind.Utc).ToLocalTime ();
708 public static DateTime SpecifyKind (DateTime value, DateTimeKind kind)
710 return new DateTime (value.Ticks, kind);
715 internal long ToBinary ()
720 internal static DateTime FromBinary (long dateData)
722 return new DateTime (dateData & 0x3fffffffffffffff);
726 public static int DaysInMonth (int year, int month)
730 if (month < 1 || month >12)
731 throw new ArgumentOutOfRangeException ();
733 if (year < 1 || year > 9999)
734 throw new ArgumentOutOfRangeException ();
736 days = (IsLeapYear(year) ? daysmonthleap : daysmonth);
740 public override bool Equals (object o)
742 if (!(o is System.DateTime))
745 return ((DateTime) o).ticks == ticks;
748 public static bool Equals (DateTime t1, DateTime t2 )
750 return (t1.ticks == t2.ticks );
753 public static DateTime FromFileTime (long fileTime)
756 throw new ArgumentOutOfRangeException ("fileTime", "< 0");
758 return new DateTime (w32file_epoch + fileTime).ToLocalTime ();
762 public static DateTime FromFileTimeUtc (long fileTime)
765 throw new ArgumentOutOfRangeException ("fileTime", "< 0");
767 return new DateTime (w32file_epoch + fileTime);
771 public static DateTime FromOADate (double d)
773 // An OLE Automation date is implemented as a floating-point number
774 // whose value is the number of days from midnight, 30 December 1899.
776 // d must be negative 657435.0 through positive 2958466.0.
777 if ((d <= OAMinValue) || (d >= OAMaxValue))
778 throw new ArgumentException ("d", "[-657435,2958466]");
780 DateTime dt = new DateTime (ticks18991230);
782 Double days = Math.Ceiling (d);
783 // integer part is the number of days (negative)
784 dt = dt.AddRoundedMilliseconds (days * 86400000);
785 // but decimals are the number of hours (in days fractions) and positive
786 Double hours = (days - d);
787 dt = dt.AddRoundedMilliseconds (hours * 86400000);
790 dt = dt.AddRoundedMilliseconds (d * 86400000);
796 public string[] GetDateTimeFormats()
798 return GetDateTimeFormats (CultureInfo.CurrentCulture);
801 public string[] GetDateTimeFormats(char format)
803 if ("dDgGfFmMrRstTuUyY".IndexOf (format) < 0)
804 throw new FormatException ("Invalid format character.");
805 string[] result = new string[1];
806 result[0] = this.ToString(format.ToString());
810 public string[] GetDateTimeFormats(IFormatProvider provider)
812 DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
813 // return GetDateTimeFormats (info.GetAllDateTimePatterns ());
814 ArrayList al = new ArrayList ();
815 foreach (char c in "dDgGfFmMrRstTuUyY")
816 al.AddRange (GetDateTimeFormats (c, info));
817 return al.ToArray (typeof (string)) as string [];
820 public string[] GetDateTimeFormats(char format,IFormatProvider provider )
822 if ("dDgGfFmMrRstTuUyY".IndexOf (format) < 0)
823 throw new FormatException ("Invalid format character.");
825 // LAMESPEC: There is NO assurance that 'U' ALWAYS
826 // euqals to 'F', but since we have to iterate all
827 // the pattern strings, we cannot just use
828 // ToString("U", provider) here. I believe that the
829 // method's behavior cannot be formalized.
830 bool adjustutc = false;
839 DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
840 return GetDateTimeFormats (adjustutc, info.GetAllRawDateTimePatterns (format), info);
843 private string [] GetDateTimeFormats (bool adjustutc, string [] patterns, DateTimeFormatInfo dfi)
845 string [] results = new string [patterns.Length];
846 DateTime val = adjustutc ? ToUniversalTime () : this;
847 for (int i = 0; i < results.Length; i++)
848 results [i] = DateTimeUtils.ToString (val, patterns [i], dfi);
853 private void CheckDateTimeKind (DateTimeKind kind) {
854 if ((kind != DateTimeKind.Unspecified) && (kind != DateTimeKind.Utc) && (kind != DateTimeKind.Local))
855 throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
859 public override int GetHashCode ()
861 return (int) ticks.Ticks;
864 public TypeCode GetTypeCode ()
866 return TypeCode.DateTime;
869 public static bool IsLeapYear (int year)
871 if (year < 1 || year > 9999)
872 throw new ArgumentOutOfRangeException ();
873 return ( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ;
876 public static DateTime Parse (string s)
878 return Parse (s, null);
881 public static DateTime Parse (string s, IFormatProvider fp)
883 return Parse (s, fp, DateTimeStyles.AllowWhiteSpaces);
886 public static DateTime Parse (string s, IFormatProvider fp, DateTimeStyles styles)
889 const string formatExceptionMessage = "String was not recognized as a valid DateTime.";
891 const string argumentYearRangeExceptionMessage = "Valid values are between 1 and 9999, inclusive.";
895 throw new ArgumentNullException (Locale.GetText ("s is null"));
897 fp = CultureInfo.CurrentCulture;
898 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (fp);
900 bool longYear = false;
902 // Try first all the combinations of ParseAllDateFormats & ParseTimeFormats
903 string[] allDateFormats = YearMonthDayFormats (dfi);
904 for (int i = 0; i < allDateFormats.Length; i++) {
905 string firstPart = allDateFormats [i];
906 bool incompleteFormat = false;
907 if (_DoParse (s, firstPart, "", false, out result, dfi, styles, true, ref incompleteFormat, ref longYear))
909 if (!incompleteFormat)
912 for (int j = 0; j < ParseTimeFormats.Length; j++) {
913 if (_DoParse (s, firstPart, ParseTimeFormats [j], false, out result, dfi, styles, true, ref incompleteFormat, ref longYear))
917 string[] monthDayFormats = IsDayBeforeMonth (dfi) ? DayMonthShortFormats : MonthDayShortFormats;
918 for (int i = 0; i < monthDayFormats.Length; i++) {
919 bool incompleteFormat = false;
920 if (_DoParse (s, monthDayFormats[i], "", false, out result, dfi, styles, true, ref incompleteFormat, ref longYear))
923 for (int j = 0; j < ParseTimeFormats.Length; j++) {
924 string firstPart = ParseTimeFormats [j];
925 bool incompleteFormat = false;
926 if (_DoParse (s, firstPart, "", false, out result, dfi, styles, false, ref incompleteFormat, ref longYear))
928 if (!incompleteFormat)
931 for (int i = 0; i < monthDayFormats.Length; i++) {
932 if (_DoParse (s, firstPart, monthDayFormats [i], false, out result, dfi, styles, false, ref incompleteFormat, ref longYear))
935 for (int i = 0; i < allDateFormats.Length; i++) {
936 string dateFormat = allDateFormats [i];
937 if (dateFormat[dateFormat.Length - 1] == 'T')
938 continue; // T formats must be before the time part
939 if (_DoParse (s, firstPart, dateFormat, false, out result, dfi, styles, false, ref incompleteFormat, ref longYear))
944 // Try as a last resort all the patterns
945 if (ParseExact (s, dfi.GetAllDateTimePatternsInternal (), dfi, styles, out result, false, ref longYear))
949 // .NET does not throw an ArgumentOutOfRangeException, but .NET 1.1 does.
950 throw new FormatException (formatExceptionMessage);
953 throw new ArgumentOutOfRangeException ("year",
954 argumentYearRangeExceptionMessage);
957 throw new FormatException (formatExceptionMessage);
961 public static DateTime ParseExact (string s, string format, IFormatProvider fp)
963 return ParseExact (s, format, fp, DateTimeStyles.None);
966 private static bool IsDayBeforeMonth (DateTimeFormatInfo dfi)
968 int dayIndex = dfi.MonthDayPattern.IndexOf('d');
969 int monthIndex = dfi.MonthDayPattern.IndexOf('M');
970 if (dayIndex == -1 || monthIndex == -1)
971 throw new FormatException (Locale.GetText("Order of month and date is not defined by {0}", dfi.MonthDayPattern));
973 return dayIndex < monthIndex;
976 private static string[] YearMonthDayFormats (DateTimeFormatInfo dfi)
978 int dayIndex = dfi.ShortDatePattern.IndexOf('d');
979 int monthIndex = dfi.ShortDatePattern.IndexOf('M');
980 int yearIndex = dfi.ShortDatePattern.IndexOf('y');
981 if (dayIndex == -1 || monthIndex == -1 || yearIndex == -1)
982 throw new FormatException (Locale.GetText("Order of year, month and date is not defined by {0}", dfi.ShortDatePattern));
984 if (yearIndex < monthIndex)
985 if (monthIndex < dayIndex)
986 return ParseYearMonthDayFormats;
987 else if (yearIndex < dayIndex)
988 return ParseYearDayMonthFormats;
990 // The year cannot be between the date and the month
991 throw new FormatException (Locale.GetText("Order of date, year and month defined by {0} is not supported", dfi.ShortDatePattern));
992 else if (dayIndex < monthIndex)
993 return ParseDayMonthYearFormats;
994 else if (dayIndex < yearIndex)
995 return ParseMonthDayYearFormats;
997 // The year cannot be between the month and the date
998 throw new FormatException (Locale.GetText("Order of month, year and date defined by {0} is not supported", dfi.ShortDatePattern));
1001 private static int _ParseNumber (string s, int valuePos,
1005 bool sloppy_parsing,
1011 leadingzero = false;
1014 int real_digits = 0;
1015 for (i = valuePos; i < s.Length && i < digits + valuePos; i++) {
1016 if (!Char.IsDigit (s[i]))
1022 digits = real_digits;
1024 if (digits < min_digits) {
1029 if (s.Length - valuePos < digits) {
1034 for (i = valuePos; i < digits + valuePos; i++) {
1036 if (!Char.IsDigit (c)) {
1041 number = number * 10 + (byte) (c - '0');
1044 num_parsed = digits;
1048 private static int _ParseEnum (string s, int sPos, string[] values, string[] invValues, bool exact, out int num_parsed)
1050 // FIXME: I know this is somehow lame code. Probably
1051 // it should iterate all the enum value and return
1052 // the longest match. However right now I don't see
1053 // anything but "1" and "10" - "12" that might match
1054 // two or more values. (They are only abbrev month
1055 // names, so do reverse order search). See bug #80094.
1056 for (int i = values.Length - 1; i >= 0; i--) {
1057 if (!exact && invValues [i].Length > values[i].Length) {
1058 if (invValues [i].Length > 0 && _ParseString (s, sPos, 0, invValues [i], out num_parsed))
1060 if (values [i].Length > 0 && _ParseString (s, sPos, 0, values [i], out num_parsed))
1064 if (values [i].Length > 0 && _ParseString (s, sPos, 0, values [i], out num_parsed))
1066 if (!exact && invValues [i].Length > 0 && _ParseString (s, sPos, 0, invValues [i], out num_parsed))
1075 private static bool _ParseString (string s, int sPos, int maxlength, string value, out int num_parsed)
1078 maxlength = value.Length;
1080 if (sPos + maxlength <= s.Length && String.Compare (s, sPos, value, 0, maxlength, true, CultureInfo.InvariantCulture) == 0) {
1081 num_parsed = maxlength;
1089 // Note that in case of Parse (exact == false) we check both for AM/PM
1090 // and the culture spcific AM/PM strings.
1091 private static bool _ParseAmPm(string s,
1094 DateTimeFormatInfo dfi,
1103 if (!IsLetter (s, valuePos)) {
1104 if (dfi.AMDesignator != "")
1111 DateTimeFormatInfo invInfo = DateTimeFormatInfo.InvariantInfo;
1112 if (!exact && _ParseString (s, valuePos, num, invInfo.PMDesignator, out num_parsed) ||
1113 dfi.PMDesignator != "" && _ParseString(s, valuePos, num, dfi.PMDesignator, out num_parsed))
1115 else if (!exact && _ParseString (s, valuePos, num, invInfo.AMDesignator, out num_parsed) ||
1116 _ParseString (s, valuePos, num, dfi.AMDesignator, out num_parsed)) {
1117 if (exact || num_parsed != 0)
1125 // Note that in case of Parse (exact == false) we check both for ':'
1126 // and the culture spcific TimeSperator
1127 private static bool _ParseTimeSeparator (string s, int sPos, DateTimeFormatInfo dfi, bool exact, out int num_parsed)
1129 return _ParseString (s, sPos, 0, dfi.TimeSeparator, out num_parsed) ||
1130 !exact && _ParseString (s, sPos, 0, ":", out num_parsed);
1133 // Accept any character for DateSeparator, except TimeSeparator,
1134 // a digit or a letter.
1135 // Not documented, but seems to be MS behaviour here. See bug 54047.
1136 private static bool _ParseDateSeparator (string s, int sPos, DateTimeFormatInfo dfi, bool exact, out int num_parsed)
1139 if (exact && s [sPos] != '/')
1142 if (_ParseTimeSeparator (s, sPos, dfi, exact, out num_parsed) ||
1143 Char.IsDigit (s [sPos]) || Char.IsLetter (s [sPos]))
1150 private static bool IsLetter (string s, int pos)
1152 return pos < s.Length && Char.IsLetter (s [pos]);
1155 // To implement better DateTime.Parse we use two format strings one
1156 // for Date and one for Time. This allows us to define two different
1157 // arrays of formats for Time and Dates and to combine them more or less
1158 // efficiently. When this mode is used flexibleTwoPartsParsing is true.
1159 private static bool _DoParse (string s,
1163 out DateTime result,
1164 DateTimeFormatInfo dfi,
1165 DateTimeStyles style,
1166 bool firstPartIsDate,
1167 ref bool incompleteFormat,
1170 bool useutc = false;
1171 bool use_invariant = false;
1172 bool sloppy_parsing = false;
1174 bool afterTimePart = firstPartIsDate && secondPart == "";
1176 bool flexibleTwoPartsParsing = !exact && secondPart != null;
1177 incompleteFormat = false;
1179 string format = firstPart;
1180 bool afterTFormat = false;
1181 DateTimeFormatInfo invInfo = DateTimeFormatInfo.InvariantInfo;
1182 if (format.Length == 1)
1183 format = DateTimeUtils.GetStandardPattern (format [0], dfi, out useutc, out use_invariant);
1185 result = new DateTime (0);
1189 if ((style & DateTimeStyles.AllowLeadingWhite) != 0) {
1190 format = format.TrimStart (null);
1192 s = s.TrimStart (null); // it could be optimized, but will make little good.
1195 if ((style & DateTimeStyles.AllowTrailingWhite) != 0) {
1196 format = format.TrimEnd (null);
1197 s = s.TrimEnd (null); // it could be optimized, but will make little good.
1203 if ((style & DateTimeStyles.AllowInnerWhite) != 0)
1204 sloppy_parsing = true;
1206 string chars = format;
1207 int len = format.Length, pos = 0, num = 0;
1211 int day = -1, dayofweek = -1, month = -1, year = -1;
1212 int hour = -1, minute = -1, second = -1;
1213 double fractionalSeconds = -1;
1215 int tzsign = -1, tzoffset = -1, tzoffmin = -1;
1216 bool isFirstPart = true;
1220 if (valuePos == s.Length)
1224 if (flexibleTwoPartsParsing && pos + num == 0)
1226 bool isLetter = IsLetter(s, valuePos);
1230 if (afterTimePart && isLetter) {
1232 if (s [valuePos] == 'Z')
1235 _ParseString (s, valuePos, 0, "GMT", out num_parsed);
1236 if (num_parsed > 0 && !IsLetter (s, valuePos + num_parsed)) {
1237 valuePos += num_parsed;
1242 if (!afterTFormat && _ParseAmPm (s, valuePos, 0, dfi, exact, out num_parsed, ref ampm)) {
1243 if (IsLetter (s, valuePos + num_parsed))
1245 else if (num_parsed > 0) {
1246 valuePos += num_parsed;
1251 if (!afterTFormat && dayofweek == -1 && isLetter) {
1252 dayofweek = _ParseEnum (s, valuePos, dfi.RawDayNames, invInfo.RawDayNames, exact, out num_parsed);
1253 if (dayofweek == -1)
1254 dayofweek = _ParseEnum (s, valuePos, dfi.RawAbbreviatedDayNames, invInfo.RawAbbreviatedDayNames, exact, out num_parsed);
1255 if (dayofweek != -1 && !IsLetter (s, valuePos + num_parsed)) {
1256 valuePos += num_parsed;
1263 if (char.IsWhiteSpace (s [valuePos]) || s [valuePos] == ',') {
1270 if (pos + num >= len)
1272 if (flexibleTwoPartsParsing && num == 0) {
1273 afterTFormat = isFirstPart && firstPart [firstPart.Length - 1] == 'T';
1274 if (!isFirstPart && format == "")
1279 format = secondPart;
1284 isFirstPart = false;
1286 if (!firstPartIsDate || format == "")
1287 afterTimePart = true;
1294 bool leading_zeros = true;
1296 if (chars[pos] == '\'') {
1298 while (pos+num < len) {
1299 if (chars[pos+num] == '\'')
1302 if (valuePos == s.Length || s [valuePos] != chars [pos + num])
1312 } else if (chars[pos] == '"') {
1314 while (pos+num < len) {
1315 if (chars[pos+num] == '"')
1318 if (valuePos == s.Length || s [valuePos] != chars[pos+num])
1328 } else if (chars[pos] == '\\') {
1333 if (s [valuePos] != chars [pos])
1339 } else if (chars[pos] == '%') {
1342 } else if (char.IsWhiteSpace (s [valuePos]) ||
1343 s [valuePos] == ',' && (!exact && chars [pos] == '/' || Char.IsWhiteSpace (chars [pos]))) {
1346 if (exact && (style & DateTimeStyles.AllowInnerWhite) == 0) {
1347 if (!Char.IsWhiteSpace (chars[pos]))
1354 while (ws < s.Length) {
1355 if (Char.IsWhiteSpace (s [ws]) || s [ws] == ',')
1362 while (ws < chars.Length) {
1363 if (Char.IsWhiteSpace (chars [ws]) || chars [ws] == ',')
1369 // A whitespace may match a '/' in the pattern.
1370 if (!exact && pos < chars.Length && chars[pos] == '/')
1371 if (!_ParseDateSeparator (s, valuePos, dfi, exact, out num_parsed))
1376 if ((pos+num+1 < len) && (chars[pos+num+1] == chars[pos+num])) {
1384 if (num < 2 && day != -1 || num >= 2 && dayofweek != -1)
1387 day = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1389 day = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1391 dayofweek = _ParseEnum (s, valuePos, dfi.RawAbbreviatedDayNames, invInfo.RawAbbreviatedDayNames, exact, out num_parsed);
1393 dayofweek = _ParseEnum (s, valuePos, dfi.RawDayNames, invInfo.RawDayNames, exact, out num_parsed);
1399 if (flexibleTwoPartsParsing) {
1401 if (num == 0 || num == 3)
1402 month = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1403 if (num > 1 && num_parsed == -1)
1404 month = _ParseEnum (s, valuePos, dfi.RawMonthNames, invInfo.RawMonthNames, exact, out num_parsed) + 1;
1405 if (num > 1 && num_parsed == -1)
1406 month = _ParseEnum (s, valuePos, dfi.RawAbbreviatedMonthNames, invInfo.RawAbbreviatedMonthNames, exact, out num_parsed) + 1;
1411 month = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1413 month = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1415 month = _ParseEnum (s, valuePos, dfi.RawAbbreviatedMonthNames, invInfo.RawAbbreviatedMonthNames, exact, out num_parsed) + 1;
1417 month = _ParseEnum (s, valuePos, dfi.RawMonthNames, invInfo.RawMonthNames, exact, out num_parsed) + 1;
1424 year = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1425 } else if (num < 3) {
1426 year = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1428 year = _ParseNumber (s, valuePos, exact ? 4 : 3, 4, false, sloppy_parsing, out num_parsed);
1429 if ((year >= 1000) && (num_parsed == 4) && (!longYear) && (s.Length > 4 + valuePos)) {
1431 int ly = _ParseNumber (s, valuePos, 5, 5, false, sloppy_parsing, out np);
1432 longYear = (ly > 9999);
1437 //FIXME: We should do use dfi.Calendat.TwoDigitYearMax
1438 if (num_parsed <= 2)
1439 year += (year < 30) ? 2000 : 1900;
1445 hour = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1447 hour = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1456 if (hour != -1 || !flexibleTwoPartsParsing && ampm >= 0)
1459 hour = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1461 hour = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1472 minute = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1474 minute = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1484 second = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1486 second = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1494 leading_zeros = false;
1498 if (num > 6 || fractionalSeconds != -1)
1500 double decimalNumber = (double) _ParseNumber (s, valuePos, 0, num+1, leading_zeros, sloppy_parsing, out num_parsed);
1501 if (num_parsed == -1)
1503 fractionalSeconds = decimalNumber / Math.Pow(10.0, num_parsed);
1506 if (!_ParseAmPm (s, valuePos, num > 0 ? 0 : 1, dfi, exact, out num_parsed, ref ampm))
1513 if (s [valuePos] == '+')
1515 else if (s [valuePos] == '-')
1522 tzoffset = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1524 tzoffset = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1526 tzoffset = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1527 valuePos += num_parsed;
1532 if (valuePos < s.Length && Char.IsDigit (s [valuePos]) ||
1533 _ParseTimeSeparator (s, valuePos, dfi, exact, out num_parsed)) {
1534 valuePos += num_parsed;
1535 tzoffmin = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1539 else if (!flexibleTwoPartsParsing)
1547 if (s [valuePos] == 'Z') {
1551 else if (s [valuePos] == '+' || s [valuePos] == '-') {
1554 if (s [valuePos] == '+')
1556 else if (s [valuePos] == '-')
1561 tzoffset = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1562 valuePos += num_parsed;
1566 if (Char.IsDigit (s [valuePos]))
1568 else if (!_ParseString (s, valuePos, 0, dfi.TimeSeparator, out num_parsed))
1570 valuePos += num_parsed;
1572 tzoffmin = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1579 // LAMESPEC: This should be part of UTCpattern
1580 // string and thus should not be considered here.
1582 // Note that 'Z' is not defined as a pattern
1583 // character. Keep it for X509 certificate
1584 // verification. Also, "Z" != "'Z'" under MS.NET
1585 // ("'Z'" is just literal; handled above)
1587 if (s [valuePos] != 'Z')
1594 if (s [valuePos] != 'G')
1597 if ((pos + 2 < len) && (valuePos + 2 < s.Length) &&
1598 (chars [pos + 1] == 'M') && (s[valuePos + 1] == 'M') &&
1599 (chars [pos + 2] == 'T') && (s[valuePos + 2] == 'T'))
1611 if (!_ParseTimeSeparator (s, valuePos, dfi, exact, out num_parsed))
1615 if (!_ParseDateSeparator (s, valuePos, dfi, exact, out num_parsed))
1621 if (s [valuePos] != chars [pos])
1632 valuePos += num_parsed;
1634 if (!exact && !flexibleTwoPartsParsing) {
1635 switch (chars [pos]) {
1643 if (s.Length > valuePos && s [valuePos] == 'Z' &&
1644 (pos + 1 == chars.Length || chars [pos + 1] != 'Z')) {
1652 pos = pos + num + 1;
1657 while (pos < len && chars [pos] == 'K') // 'K' can be mapped to nothing
1663 if (s.Length > valuePos) // extraneous tail.
1668 if (Char.IsDigit (s [valuePos]) && Char.IsDigit (s [valuePos - 1]))
1670 if (Char.IsLetter (s [valuePos]) && Char.IsLetter (s [valuePos - 1]))
1672 incompleteFormat = true;
1683 if (fractionalSeconds == -1)
1684 fractionalSeconds = 0;
1686 // If no date was given
1687 if ((day == -1) && (month == -1) && (year == -1)) {
1688 if ((style & DateTimeStyles.NoCurrentDateDefault) != 0) {
1693 day = DateTime.Today.Day;
1694 month = DateTime.Today.Month;
1695 year = DateTime.Today.Year;
1704 if ((style & DateTimeStyles.NoCurrentDateDefault) != 0)
1707 year = DateTime.Today.Year;
1710 if (ampm == 0 && hour == 12)
1713 if (ampm == 1 && (!flexibleTwoPartsParsing || hour < 12))
1716 // For anything out of range
1718 if (year < 1 || year > 9999 ||
1719 month < 1 || month >12 ||
1720 day < 1 || day > DateTime.DaysInMonth(year, month) ||
1721 hour < 0 || hour > 23 ||
1722 minute < 0 || minute > 59 ||
1723 second < 0 || second > 59)
1726 result = new DateTime (year, month, day, hour, minute, second, 0);
1727 result = result.AddSeconds(fractionalSeconds);
1729 if (dayofweek != -1 && dayofweek != (int) result.DayOfWeek)
1732 bool kind_specified = true;
1735 bool adjustToUniversal = (style & DateTimeStyles.AdjustToUniversal) != 0;
1743 tzoffset = -tzoffset;
1745 utcoffset = new TimeSpan (tzoffset, tzoffmin, 0);
1746 long newticks = (result.ticks - utcoffset).Ticks;
1748 newticks += TimeSpan.TicksPerDay;
1749 result = new DateTime (false, new TimeSpan (newticks));
1751 result.kind = DateTimeKind.Utc;
1752 if ((style & DateTimeStyles.RoundtripKind) != 0)
1753 result = result.ToLocalTime ();
1757 else if (useutc || ((style & DateTimeStyles.AssumeUniversal) != 0))
1758 result.kind = DateTimeKind.Utc;
1759 else if ((style & DateTimeStyles.AssumeLocal) != 0)
1760 result.kind = DateTimeKind.Local;
1762 bool adjustToLocal = !adjustToUniversal && (style & DateTimeStyles.RoundtripKind) == 0;
1763 if (result.kind != DateTimeKind.Unspecified)
1765 if (adjustToUniversal)
1766 result = result.ToUniversalTime ();
1767 else if (adjustToLocal)
1768 result = result.ToLocalTime ();
1771 if (!adjustToUniversal && (useutc || tzsign != -1))
1772 result = result.ToLocalTime ();
1777 public static DateTime ParseExact (string s, string format,
1778 IFormatProvider fp, DateTimeStyles style)
1781 throw new ArgumentNullException ("format");
1783 string [] formats = new string [1];
1784 formats[0] = format;
1786 return ParseExact (s, formats, fp, style);
1789 public static DateTime ParseExact (string s, string[] formats,
1791 DateTimeStyles style)
1793 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (fp);
1798 throw new ArgumentNullException ("s");
1799 if (formats == null)
1800 throw new ArgumentNullException ("formats");
1801 if (formats.Length == 0)
1802 throw new FormatException ("Format specifier was invalid.");
1805 bool longYear = false;
1806 if (!ParseExact (s, formats, dfi, style, out result, true, ref longYear))
1807 throw new FormatException ();
1812 private static void CheckStyle (DateTimeStyles style)
1814 if ( (style & DateTimeStyles.RoundtripKind) != 0)
1816 if ((style & DateTimeStyles.AdjustToUniversal) != 0 || (style & DateTimeStyles.AssumeLocal) != 0 ||
1817 (style & DateTimeStyles.AssumeUniversal) != 0)
1818 throw new ArgumentException ("The DateTimeStyles value RoundtripKind cannot be used with the values AssumeLocal, Asersal or AdjustToUniversal.", "style");
1820 if ((style & DateTimeStyles.AssumeUniversal) != 0 && (style & DateTimeStyles.AssumeLocal) != 0)
1821 throw new ArgumentException ("The DateTimeStyles values AssumeLocal and AssumeUniversal cannot be used together.", "style");
1824 public static bool TryParse (string s, out DateTime result)
1835 public static bool TryParse (string s, IFormatProvider provider, DateTimeStyles styles, out DateTime result)
1838 result = Parse (s, provider, styles);
1846 public static bool TryParseExact (string s, string format,
1848 DateTimeStyles style,
1849 out DateTime result)
1853 formats = new string [1];
1854 formats[0] = format;
1856 return TryParseExact (s, formats, fp, style, out result);
1859 public static bool TryParseExact (string s, string[] formats,
1861 DateTimeStyles style,
1862 out DateTime result)
1864 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (fp);
1866 bool longYear = false;
1867 return ParseExact (s, formats, dfi, style, out result, true, ref longYear);
1871 private static bool ParseExact (string s, string [] formats,
1872 DateTimeFormatInfo dfi, DateTimeStyles style, out DateTime ret,
1873 bool exact, ref bool longYear)
1876 bool incompleteFormat = false;
1877 for (i = 0; i < formats.Length; i++)
1880 string format = formats[i];
1881 if (format == null || format == String.Empty)
1882 throw new FormatException ("Invalid Format String");
1884 if (_DoParse (s, formats[i], null, exact, out result, dfi, style, false, ref incompleteFormat, ref longYear)) {
1889 ret = DateTime.MinValue;
1893 public TimeSpan Subtract(DateTime dt)
1895 return new TimeSpan(ticks.Ticks) - dt.ticks;
1898 public DateTime Subtract(TimeSpan ts)
1902 newticks = (new TimeSpan (ticks.Ticks)) - ts;
1903 DateTime ret = new DateTime(true,newticks);
1910 public long ToFileTime()
1912 DateTime universalTime = ToUniversalTime();
1914 if (universalTime.Ticks < w32file_epoch) {
1915 throw new ArgumentOutOfRangeException("file time is not valid");
1918 return(universalTime.Ticks - w32file_epoch);
1922 public long ToFileTimeUtc()
1924 if (Ticks < w32file_epoch) {
1925 throw new ArgumentOutOfRangeException("file time is not valid");
1928 return (Ticks - w32file_epoch);
1932 public string ToLongDateString()
1934 return ToString ("D");
1937 public string ToLongTimeString()
1939 return ToString ("T");
1942 public double ToOADate ()
1944 long t = this.Ticks;
1945 // uninitialized DateTime case
1948 // we can't reach minimum value
1949 if (t < 31242239136000000)
1950 return OAMinValue + 0.001;
1952 TimeSpan ts = new TimeSpan (this.Ticks - ticks18991230);
1953 double result = ts.TotalDays;
1954 // t < 0 (where 599264352000000000 == 0.0d for OA)
1955 if (t < 599264352000000000) {
1956 // negative days (int) but decimals are positive
1957 double d = Math.Ceiling (result);
1958 result = d - 2 - (result - d);
1961 // we can't reach maximum value
1962 if (result >= OAMaxValue)
1963 result = OAMaxValue - 0.00000001d;
1968 public string ToShortDateString()
1970 return ToString ("d");
1973 public string ToShortTimeString()
1975 return ToString ("t");
1978 public override string ToString ()
1980 return ToString ("G", null);
1983 public string ToString (IFormatProvider fp)
1985 return ToString (null, fp);
1988 public string ToString (string format)
1990 return ToString (format, null);
1993 public string ToString (string format, IFormatProvider fp)
1995 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance(fp);
1997 if (format == null || format == String.Empty)
2000 bool useutc = false, use_invariant = false;
2002 if (format.Length == 1) {
2003 char fchar = format [0];
2004 format = DateTimeUtils.GetStandardPattern (fchar, dfi, out useutc, out use_invariant);
2006 return DateTimeUtils.ToString (ToUniversalTime (), format, dfi);
2007 // return ToUniversalTime()._ToString (format, dfi);
2010 throw new FormatException ("format is not one of the format specifier characters defined for DateTimeFormatInfo");
2013 // Don't convert UTC value. It just adds 'Z' for
2014 // 'u' format, for the same ticks.
2015 return DateTimeUtils.ToString (this, format, dfi);
2018 public DateTime ToLocalTime ()
2020 return TimeZone.CurrentTimeZone.ToLocalTime (this);
2023 public DateTime ToUniversalTime()
2025 return TimeZone.CurrentTimeZone.ToUniversalTime (this);
2030 public static DateTime operator +(DateTime d, TimeSpan t)
2032 DateTime ret = new DateTime (true, d.ticks + t);
2039 public static bool operator ==(DateTime d1, DateTime d2)
2041 return (d1.ticks == d2.ticks);
2044 public static bool operator >(DateTime t1,DateTime t2)
2046 return (t1.ticks > t2.ticks);
2049 public static bool operator >=(DateTime t1,DateTime t2)
2051 return (t1.ticks >= t2.ticks);
2054 public static bool operator !=(DateTime d1, DateTime d2)
2056 return (d1.ticks != d2.ticks);
2059 public static bool operator <(DateTime t1, DateTime t2)
2061 return (t1.ticks < t2.ticks );
2064 public static bool operator <=(DateTime t1,DateTime t2)
2066 return (t1.ticks <= t2.ticks);
2069 public static TimeSpan operator -(DateTime d1,DateTime d2)
2071 return new TimeSpan((d1.ticks - d2.ticks).Ticks);
2074 public static DateTime operator -(DateTime d,TimeSpan t)
2076 DateTime ret = new DateTime (true, d.ticks - t);
2083 bool IConvertible.ToBoolean(IFormatProvider provider)
2085 throw new InvalidCastException();
2088 byte IConvertible.ToByte(IFormatProvider provider)
2090 throw new InvalidCastException();
2094 char IConvertible.ToChar(IFormatProvider provider)
2096 throw new InvalidCastException();
2099 System.DateTime IConvertible.ToDateTime(IFormatProvider provider)
2104 decimal IConvertible.ToDecimal(IFormatProvider provider)
2106 throw new InvalidCastException();
2109 double IConvertible.ToDouble(IFormatProvider provider)
2111 throw new InvalidCastException();
2114 Int16 IConvertible.ToInt16(IFormatProvider provider)
2116 throw new InvalidCastException();
2119 Int32 IConvertible.ToInt32(IFormatProvider provider)
2121 throw new InvalidCastException();
2124 Int64 IConvertible.ToInt64(IFormatProvider provider)
2126 throw new InvalidCastException();
2129 SByte IConvertible.ToSByte(IFormatProvider provider)
2131 throw new InvalidCastException();
2134 Single IConvertible.ToSingle(IFormatProvider provider)
2136 throw new InvalidCastException();
2139 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
2141 if (conversionType == null)
2142 throw new ArgumentNullException ("conversionType");
2144 if (conversionType == typeof (DateTime))
2146 else if (conversionType == typeof (String))
2147 return this.ToString (provider);
2148 else if (conversionType == typeof (Object))
2151 throw new InvalidCastException();
2154 UInt16 IConvertible.ToUInt16(IFormatProvider provider)
2156 throw new InvalidCastException();
2159 UInt32 IConvertible.ToUInt32(IFormatProvider provider)
2161 throw new InvalidCastException();
2164 UInt64 IConvertible.ToUInt64(IFormatProvider provider)
2166 throw new InvalidCastException();