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, IComparable<DateTime>, IEquatable <DateTime>
49 private TimeSpan ticks;
53 private const int dp400 = 146097;
54 private const int dp100 = 36524;
55 private const int dp4 = 1461;
57 // w32 file time starts counting from 1/1/1601 00:00 GMT
58 // which is the constant ticks from the .NET epoch
59 private const long w32file_epoch = 504911232000000000L;
61 //private const long MAX_VALUE_TICKS = 3155378975400000000L;
62 // -- Microsoft .NET has this value.
63 private const long MAX_VALUE_TICKS = 3155378975999999999L;
66 // The UnixEpoch, it begins on Jan 1, 1970 at 0:0:0, expressed
69 internal const long UnixEpoch = 621355968000000000L;
71 // for OLE Automation dates
72 private const long ticks18991230 = 599264352000000000L;
73 private const double OAMinValue = -657435.0d;
74 private const double OAMaxValue = 2958466.0d;
76 public static readonly DateTime MaxValue = new DateTime (false, new TimeSpan (MAX_VALUE_TICKS));
77 public static readonly DateTime MinValue = new DateTime (false, new TimeSpan (0));
79 // DateTime.Parse patterns
80 // Patterns are divided to date and time patterns. The algorithm will
81 // try combinations of these patterns. The algorithm also looks for
82 // day of the week, AM/PM GMT and Z independently of the patterns.
83 private static readonly string[] ParseTimeFormats = new string [] {
91 "H tt", // Specifies AM to disallow '8'.
92 "H'\u6642'm'\u5206's'\u79D2'",
95 // DateTime.Parse date patterns extend ParseExact patterns as follows:
96 // MMM - month short name or month full name
97 // MMMM - month number or short name or month full name
99 // Parse behaves differently according to the ShorDatePattern of the
100 // DateTimeFormatInfo. The following define the date patterns for
101 // different orders of day, month and year in ShorDatePattern.
102 // Note that the year cannot go between the day and the month.
103 private static readonly string[] ParseYearDayMonthFormats = new string [] {
106 "yyyy'\u5E74'M'\u6708'd'\u65E5",
119 private static readonly string[] ParseYearMonthDayFormats = new string [] {
122 "yyyy'\u5E74'M'\u6708'd'\u65E5",
136 private static readonly string[] ParseDayMonthYearFormats = new string [] {
139 "yyyy'\u5E74'M'\u6708'd'\u65E5",
156 private static readonly string[] ParseMonthDayYearFormats = new string [] {
159 "yyyy'\u5E74'M'\u6708'd'\u65E5",
176 // Patterns influenced by the MonthDayPattern in DateTimeFormatInfo.
177 // Note that these patterns cannot be followed by the time.
178 private static readonly string[] MonthDayShortFormats = new string [] {
183 private static readonly string[] DayMonthShortFormats = new string [] {
197 private static readonly int[] daysmonth = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
198 private static readonly int[] daysmonthleap = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
200 private static int AbsoluteDays (int year, int month, int day)
205 days = (IsLeapYear(year) ? daysmonthleap : daysmonth);
209 return ((day-1) + temp + (365* (year-1)) + ((year-1)/4) - ((year-1)/100) + ((year-1)/400));
212 private int FromTicks(Which what)
214 int num400, num100, num4, numyears;
217 int[] days = daysmonth;
218 int totaldays = this.ticks.Days;
220 num400 = (totaldays / dp400);
221 totaldays -= num400 * dp400;
223 num100 = (totaldays / dp100);
224 if (num100 == 4) // leap
226 totaldays -= (num100 * dp100);
228 num4 = totaldays / dp4;
229 totaldays -= (num4 * dp4);
231 numyears = totaldays / 365 ;
233 if (numyears == 4) //leap
235 if (what == Which.Year )
236 return num400*400 + num100*100 + num4*4 + numyears + 1;
238 totaldays -= (numyears * 365) ;
239 if (what == Which.DayYear )
240 return totaldays + 1;
242 if ((numyears==3) && ((num100 == 3) || !(num4 == 24)) ) //31 dec leapyear
243 days = daysmonthleap;
245 while (totaldays >= days[M])
246 totaldays -= days[M++];
248 if (what == Which.Month )
258 /// Constructs a DateTime for specified ticks
261 public DateTime (long ticks)
263 this.ticks = new TimeSpan (ticks);
264 if (ticks < MinValue.Ticks || ticks > MaxValue.Ticks) {
265 string msg = Locale.GetText ("Value {0} is outside the valid range [{1},{2}].",
266 ticks, MinValue.Ticks, MaxValue.Ticks);
267 throw new ArgumentOutOfRangeException ("ticks", msg);
269 kind = DateTimeKind.Unspecified;
272 public DateTime (int year, int month, int day)
273 : this (year, month, day,0,0,0,0) {}
275 public DateTime (int year, int month, int day, int hour, int minute, int second)
276 : this (year, month, day, hour, minute, second, 0) {}
278 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond)
280 if ( year < 1 || year > 9999 ||
281 month < 1 || month >12 ||
282 day < 1 || day > DaysInMonth(year, month) ||
283 hour < 0 || hour > 23 ||
284 minute < 0 || minute > 59 ||
285 second < 0 || second > 59 ||
286 millisecond < 0 || millisecond > 999)
287 throw new ArgumentOutOfRangeException ("Parameters describe an " +
288 "unrepresentable DateTime.");
290 ticks = new TimeSpan (AbsoluteDays(year,month,day), hour, minute, second, millisecond);
292 kind = DateTimeKind.Unspecified;
295 public DateTime (int year, int month, int day, Calendar calendar)
296 : this (year, month, day, 0, 0, 0, 0, calendar)
300 public DateTime (int year, int month, int day, int hour, int minute, int second, Calendar calendar)
301 : this (year, month, day, hour, minute, second, 0, calendar)
305 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar)
307 if (calendar == null)
308 throw new ArgumentNullException ("calendar");
309 ticks = calendar.ToDateTime (year, month, day, hour, minute, second, millisecond).ticks;
310 kind = DateTimeKind.Unspecified;
313 internal DateTime (bool check, TimeSpan value)
315 if (check && (value.Ticks < MinValue.Ticks || value.Ticks > MaxValue.Ticks))
316 throw new ArgumentOutOfRangeException ();
320 kind = DateTimeKind.Unspecified;
323 public DateTime (long ticks, DateTimeKind kind) : this (ticks)
325 CheckDateTimeKind (kind);
329 public DateTime (int year, int month, int day, int hour, int minute, int second, DateTimeKind kind)
330 : this (year, month, day, hour, minute, second)
332 CheckDateTimeKind (kind);
336 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind)
337 : this (year, month, day, hour, minute, second, millisecond)
339 CheckDateTimeKind (kind);
343 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, DateTimeKind kind)
344 : this (year, month, day, hour, minute, second, millisecond, calendar)
346 CheckDateTimeKind (kind);
356 DateTime ret = new DateTime (Year, Month, Day);
366 return FromTicks(Which.Month);
374 return FromTicks(Which.Day);
378 public DayOfWeek DayOfWeek
382 return ( (DayOfWeek) ((ticks.Days+1) % 7) );
390 return FromTicks(Which.DayYear);
394 public TimeSpan TimeOfDay
398 return new TimeSpan(ticks.Ticks % TimeSpan.TicksPerDay );
415 return ticks.Minutes;
423 return ticks.Seconds;
427 public int Millisecond
431 return ticks.Milliseconds;
435 [MethodImplAttribute(MethodImplOptions.InternalCall)]
436 internal static extern long GetTimeMonotonic ();
438 [MethodImplAttribute(MethodImplOptions.InternalCall)]
439 internal static extern long GetNow ();
442 // To reduce the time consumed by DateTime.Now, we keep
443 // the difference to map the system time into a local
444 // time into `to_local_time_span', we record the timestamp
445 // for this in `last_now'
447 static object to_local_time_span_object;
448 static long last_now;
450 public static DateTime Now
454 long now = GetNow ();
455 DateTime dt = new DateTime (now);
457 if ((now - last_now) > TimeSpan.TicksPerMinute){
458 to_local_time_span_object = TimeZone.CurrentTimeZone.GetLocalTimeDiff (dt);
463 // This is boxed, so we avoid locking.
464 DateTime ret = dt + (TimeSpan) to_local_time_span_object;
465 ret.kind = DateTimeKind.Local;
478 public static DateTime Today
482 DateTime today = new DateTime (now.Year, now.Month, now.Day);
483 today.kind = now.kind;
488 public static DateTime UtcNow
491 return new DateTime (GetNow (), DateTimeKind.Utc);
499 return FromTicks(Which.Year);
503 public DateTimeKind Kind {
511 public DateTime Add (TimeSpan value)
513 DateTime ret = AddTicks (value.Ticks);
518 public DateTime AddDays (double value)
520 return AddMilliseconds (Math.Round (value * 86400000));
523 public DateTime AddTicks (long value)
525 if ((value + ticks.Ticks) > MAX_VALUE_TICKS || (value + ticks.Ticks) < 0) {
526 throw new ArgumentOutOfRangeException();
528 DateTime ret = new DateTime (value + ticks.Ticks);
533 public DateTime AddHours (double value)
535 return AddMilliseconds (value * 3600000);
538 public DateTime AddMilliseconds (double value)
540 if ((value * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
541 (value * TimeSpan.TicksPerMillisecond) < long.MinValue) {
542 throw new ArgumentOutOfRangeException();
544 long msticks = (long) (value * TimeSpan.TicksPerMillisecond);
546 return AddTicks (msticks);
549 // required to match MS implementation for OADate (OLE Automation)
550 private DateTime AddRoundedMilliseconds (double ms)
552 if ((ms * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
553 (ms * TimeSpan.TicksPerMillisecond) < long.MinValue) {
554 throw new ArgumentOutOfRangeException ();
556 long msticks = (long) (ms += ms > 0 ? 0.5 : -0.5) * TimeSpan.TicksPerMillisecond;
558 return AddTicks (msticks);
561 public DateTime AddMinutes (double value)
563 return AddMilliseconds (value * 60000);
566 public DateTime AddMonths (int months)
568 int day, month, year, maxday ;
572 month = this.Month + (months % 12);
573 year = this.Year + months/12 ;
585 maxday = DaysInMonth(year, month);
589 temp = new DateTime (year, month, day);
591 return temp.Add (this.TimeOfDay);
594 public DateTime AddSeconds (double value)
596 return AddMilliseconds (value * 1000);
599 public DateTime AddYears (int value)
601 return AddMonths (value * 12);
604 public static int Compare (DateTime t1, DateTime t2)
606 if (t1.ticks < t2.ticks)
608 else if (t1.ticks > t2.ticks)
614 public int CompareTo (object value)
619 if (!(value is System.DateTime))
620 throw new ArgumentException (Locale.GetText (
621 "Value is not a System.DateTime"));
623 return Compare (this, (DateTime) value);
626 public bool IsDaylightSavingTime ()
628 if (kind == DateTimeKind.Utc)
630 return TimeZone.CurrentTimeZone.IsDaylightSavingTime (this);
633 public int CompareTo (DateTime value)
635 return Compare (this, value);
638 public bool Equals (DateTime value)
640 return value.ticks == ticks;
643 public long ToBinary ()
646 case DateTimeKind.Utc:
647 return Ticks | 0x4000000000000000;
648 case DateTimeKind.Local:
649 return (long) ((ulong) ToUniversalTime ().Ticks | 0x8000000000000000);
655 public static DateTime FromBinary (long dateData)
657 switch ((ulong)dateData >> 62) {
659 return new DateTime (dateData ^ 0x4000000000000000, DateTimeKind.Utc);
661 return new DateTime (dateData, DateTimeKind.Unspecified);
663 return new DateTime (dateData & 0x3fffffffffffffff, DateTimeKind.Utc).ToLocalTime ();
667 public static DateTime SpecifyKind (DateTime value, DateTimeKind kind)
669 return new DateTime (value.Ticks, kind);
672 public static int DaysInMonth (int year, int month)
676 if (month < 1 || month >12)
677 throw new ArgumentOutOfRangeException ();
679 if (year < 1 || year > 9999)
680 throw new ArgumentOutOfRangeException ();
682 days = (IsLeapYear(year) ? daysmonthleap : daysmonth);
686 public override bool Equals (object value)
688 if (!(value is System.DateTime))
691 return ((DateTime) value).ticks == ticks;
694 public static bool Equals (DateTime t1, DateTime t2 )
696 return (t1.ticks == t2.ticks );
699 public static DateTime FromFileTime (long fileTime)
702 throw new ArgumentOutOfRangeException ("fileTime", "< 0");
704 return new DateTime (w32file_epoch + fileTime).ToLocalTime ();
707 public static DateTime FromFileTimeUtc (long fileTime)
710 throw new ArgumentOutOfRangeException ("fileTime", "< 0");
712 return new DateTime (w32file_epoch + fileTime);
715 public static DateTime FromOADate (double d)
717 // An OLE Automation date is implemented as a floating-point number
718 // whose value is the number of days from midnight, 30 December 1899.
720 // d must be negative 657435.0 through positive 2958466.0.
721 if ((d <= OAMinValue) || (d >= OAMaxValue))
722 throw new ArgumentException ("d", "[-657435,2958466]");
724 DateTime dt = new DateTime (ticks18991230);
726 Double days = Math.Ceiling (d);
727 // integer part is the number of days (negative)
728 dt = dt.AddRoundedMilliseconds (days * 86400000);
729 // but decimals are the number of hours (in days fractions) and positive
730 Double hours = (days - d);
731 dt = dt.AddRoundedMilliseconds (hours * 86400000);
734 dt = dt.AddRoundedMilliseconds (d * 86400000);
740 public string[] GetDateTimeFormats()
742 return GetDateTimeFormats (CultureInfo.CurrentCulture);
745 public string[] GetDateTimeFormats(char format)
747 if ("dDgGfFmMrRstTuUyY".IndexOf (format) < 0)
748 throw new FormatException ("Invalid format character.");
749 string[] result = new string[1];
750 result[0] = this.ToString(format.ToString());
754 public string[] GetDateTimeFormats(IFormatProvider provider)
756 DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
757 // return GetDateTimeFormats (info.GetAllDateTimePatterns ());
758 ArrayList al = new ArrayList ();
759 foreach (char c in "dDgGfFmMrRstTuUyY")
760 al.AddRange (GetDateTimeFormats (c, info));
761 return al.ToArray (typeof (string)) as string [];
764 public string[] GetDateTimeFormats(char format,IFormatProvider provider )
766 if ("dDgGfFmMrRstTuUyY".IndexOf (format) < 0)
767 throw new FormatException ("Invalid format character.");
769 // LAMESPEC: There is NO assurance that 'U' ALWAYS
770 // euqals to 'F', but since we have to iterate all
771 // the pattern strings, we cannot just use
772 // ToString("U", provider) here. I believe that the
773 // method's behavior cannot be formalized.
774 bool adjustutc = false;
783 DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
784 return GetDateTimeFormats (adjustutc, info.GetAllRawDateTimePatterns (format), info);
787 private string [] GetDateTimeFormats (bool adjustutc, string [] patterns, DateTimeFormatInfo dfi)
789 string [] results = new string [patterns.Length];
790 DateTime val = adjustutc ? ToUniversalTime () : this;
791 for (int i = 0; i < results.Length; i++)
792 results [i] = DateTimeUtils.ToString (val, patterns [i], dfi);
796 private void CheckDateTimeKind (DateTimeKind kind) {
797 if ((kind != DateTimeKind.Unspecified) && (kind != DateTimeKind.Utc) && (kind != DateTimeKind.Local))
798 throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
801 public override int GetHashCode ()
803 return (int) ticks.Ticks;
806 public TypeCode GetTypeCode ()
808 return TypeCode.DateTime;
811 public static bool IsLeapYear (int year)
813 if (year < 1 || year > 9999)
814 throw new ArgumentOutOfRangeException ();
815 return ( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ;
818 public static DateTime Parse (string s)
820 return Parse (s, null);
823 public static DateTime Parse (string s, IFormatProvider provider)
825 return Parse (s, provider, DateTimeStyles.AllowWhiteSpaces);
828 public static DateTime Parse (string s, IFormatProvider provider, DateTimeStyles styles)
831 throw new ArgumentNullException ("s");
835 Exception exception = null;
836 if (!CoreParse (s, provider, styles, out res, out dto, true, ref exception))
842 const string formatExceptionMessage = "String was not recognized as a valid DateTime.";
844 internal static bool CoreParse (string s, IFormatProvider provider, DateTimeStyles styles,
845 out DateTime result, out DateTimeOffset dto, bool setExceptionOnError, ref Exception exception)
847 dto = new DateTimeOffset (0, TimeSpan.Zero);
848 if (s == null || s.Length == 0) {
849 if (setExceptionOnError)
850 exception = new FormatException (formatExceptionMessage);
855 if (provider == null)
856 provider = CultureInfo.CurrentCulture;
857 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
859 // Try first all the combinations of ParseAllDateFormats & ParseTimeFormats
860 string[] allDateFormats = YearMonthDayFormats (dfi, setExceptionOnError, ref exception);
861 if (allDateFormats == null){
866 bool longYear = false;
867 for (int i = 0; i < allDateFormats.Length; i++) {
868 string firstPart = allDateFormats [i];
869 bool incompleteFormat = false;
870 if (_DoParse (s, firstPart, "", false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
873 if (!incompleteFormat)
876 for (int j = 0; j < ParseTimeFormats.Length; j++) {
877 if (_DoParse (s, firstPart, ParseTimeFormats [j], false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
885 int dayIndex = dfi.MonthDayPattern.IndexOf('d');
886 int monthIndex = dfi.MonthDayPattern.IndexOf('M');
887 if (dayIndex == -1 || monthIndex == -1){
889 if (setExceptionOnError)
890 exception = new FormatException (Locale.GetText("Order of month and date is not defined by {0}", dfi.MonthDayPattern));
893 bool is_day_before_month = dayIndex < monthIndex;
894 string[] monthDayFormats = is_day_before_month ? DayMonthShortFormats : MonthDayShortFormats;
895 for (int i = 0; i < monthDayFormats.Length; i++) {
896 bool incompleteFormat = false;
897 if (_DoParse (s, monthDayFormats[i], "", false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
901 for (int j = 0; j < ParseTimeFormats.Length; j++) {
902 string firstPart = ParseTimeFormats [j];
903 bool incompleteFormat = false;
904 if (_DoParse (s, firstPart, "", false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
906 if (!incompleteFormat)
909 for (int i = 0; i < monthDayFormats.Length; i++) {
910 if (_DoParse (s, firstPart, monthDayFormats [i], false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
913 for (int i = 0; i < allDateFormats.Length; i++) {
914 string dateFormat = allDateFormats [i];
915 if (dateFormat[dateFormat.Length - 1] == 'T')
916 continue; // T formats must be before the time part
917 if (_DoParse (s, firstPart, dateFormat, false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
922 // Try as a last resort all the patterns
923 if (ParseExact (s, dfi.GetAllDateTimePatternsInternal (), dfi, styles, out result, false, ref longYear, setExceptionOnError, ref exception))
926 if (!setExceptionOnError)
929 // .NET 2.x does not throw an ArgumentOutOfRangeException, but .NET 1.1 does.
930 exception = new FormatException (formatExceptionMessage);
934 public static DateTime ParseExact (string s, string format, IFormatProvider provider)
936 return ParseExact (s, format, provider, DateTimeStyles.None);
939 private static string[] YearMonthDayFormats (DateTimeFormatInfo dfi, bool setExceptionOnError, ref Exception exc)
941 int dayIndex = dfi.ShortDatePattern.IndexOf('d');
942 int monthIndex = dfi.ShortDatePattern.IndexOf('M');
943 int yearIndex = dfi.ShortDatePattern.IndexOf('y');
944 if (dayIndex == -1 || monthIndex == -1 || yearIndex == -1){
945 if (setExceptionOnError)
946 exc = new FormatException (Locale.GetText("Order of year, month and date is not defined by {0}", dfi.ShortDatePattern));
950 if (yearIndex < monthIndex)
951 if (monthIndex < dayIndex)
952 return ParseYearMonthDayFormats;
953 else if (yearIndex < dayIndex)
954 return ParseYearDayMonthFormats;
956 // The year cannot be between the date and the month
957 if (setExceptionOnError)
958 exc = new FormatException (Locale.GetText("Order of date, year and month defined by {0} is not supported", dfi.ShortDatePattern));
961 else if (dayIndex < monthIndex)
962 return ParseDayMonthYearFormats;
963 else if (dayIndex < yearIndex)
964 return ParseMonthDayYearFormats;
966 // The year cannot be between the month and the date
967 if (setExceptionOnError)
968 exc = new FormatException (Locale.GetText("Order of month, year and date defined by {0} is not supported", dfi.ShortDatePattern));
973 private static int _ParseNumber (string s, int valuePos,
987 for (i = valuePos; i < s.Length && i < digits + valuePos; i++) {
988 if (!Char.IsDigit (s[i]))
994 digits = real_digits;
996 if (digits < min_digits) {
1001 if (s.Length - valuePos < digits) {
1006 for (i = valuePos; i < digits + valuePos; i++) {
1008 if (!Char.IsDigit (c)) {
1013 number = number * 10 + (byte) (c - '0');
1016 num_parsed = digits;
1020 private static int _ParseEnum (string s, int sPos, string[] values, string[] invValues, bool exact, out int num_parsed)
1022 // FIXME: I know this is somehow lame code. Probably
1023 // it should iterate all the enum value and return
1024 // the longest match. However right now I don't see
1025 // anything but "1" and "10" - "12" that might match
1026 // two or more values. (They are only abbrev month
1027 // names, so do reverse order search). See bug #80094.
1028 for (int i = values.Length - 1; i >= 0; i--) {
1029 if (!exact && invValues [i].Length > values[i].Length) {
1030 if (invValues [i].Length > 0 && _ParseString (s, sPos, 0, invValues [i], out num_parsed))
1032 if (values [i].Length > 0 && _ParseString (s, sPos, 0, values [i], out num_parsed))
1036 if (values [i].Length > 0 && _ParseString (s, sPos, 0, values [i], out num_parsed))
1038 if (!exact && invValues [i].Length > 0 && _ParseString (s, sPos, 0, invValues [i], out num_parsed))
1047 private static bool _ParseString (string s, int sPos, int maxlength, string value, out int num_parsed)
1050 maxlength = value.Length;
1052 if (sPos + maxlength <= s.Length && String.Compare (s, sPos, value, 0, maxlength, true, CultureInfo.InvariantCulture) == 0) {
1053 num_parsed = maxlength;
1061 // Note that in case of Parse (exact == false) we check both for AM/PM
1062 // and the culture spcific AM/PM strings.
1063 private static bool _ParseAmPm(string s,
1066 DateTimeFormatInfo dfi,
1075 if (!IsLetter (s, valuePos)) {
1076 if (dfi.AMDesignator != "")
1083 DateTimeFormatInfo invInfo = DateTimeFormatInfo.InvariantInfo;
1084 if (!exact && _ParseString (s, valuePos, num, invInfo.PMDesignator, out num_parsed) ||
1085 dfi.PMDesignator != "" && _ParseString(s, valuePos, num, dfi.PMDesignator, out num_parsed))
1087 else if (!exact && _ParseString (s, valuePos, num, invInfo.AMDesignator, out num_parsed) ||
1088 _ParseString (s, valuePos, num, dfi.AMDesignator, out num_parsed)) {
1089 if (exact || num_parsed != 0)
1097 // Note that in case of Parse (exact == false) we check both for ':'
1098 // and the culture spcific TimeSperator
1099 private static bool _ParseTimeSeparator (string s, int sPos, DateTimeFormatInfo dfi, bool exact, out int num_parsed)
1101 return _ParseString (s, sPos, 0, dfi.TimeSeparator, out num_parsed) ||
1102 !exact && _ParseString (s, sPos, 0, ":", out num_parsed);
1105 // Accept any character for DateSeparator, except TimeSeparator,
1106 // a digit or a letter.
1107 // Not documented, but seems to be MS behaviour here. See bug 54047.
1108 private static bool _ParseDateSeparator (string s, int sPos, DateTimeFormatInfo dfi, bool exact, out int num_parsed)
1111 if (exact && s [sPos] != '/')
1114 if (_ParseTimeSeparator (s, sPos, dfi, exact, out num_parsed) ||
1115 Char.IsDigit (s [sPos]) || Char.IsLetter (s [sPos]))
1122 private static bool IsLetter (string s, int pos)
1124 return pos < s.Length && Char.IsLetter (s [pos]);
1127 // To implement better DateTime.Parse we use two format strings one
1128 // for Date and one for Time. This allows us to define two different
1129 // arrays of formats for Time and Dates and to combine them more or less
1130 // efficiently. When this mode is used flexibleTwoPartsParsing is true.
1131 private static bool _DoParse (string s,
1135 out DateTime result,
1136 out DateTimeOffset dto,
1137 DateTimeFormatInfo dfi,
1138 DateTimeStyles style,
1139 bool firstPartIsDate,
1140 ref bool incompleteFormat,
1143 bool useutc = false;
1144 bool use_invariant = false;
1145 bool sloppy_parsing = false;
1146 dto = new DateTimeOffset (0, TimeSpan.Zero);
1147 bool flexibleTwoPartsParsing = !exact && secondPart != null;
1148 incompleteFormat = false;
1150 string format = firstPart;
1151 bool afterTFormat = false;
1152 DateTimeFormatInfo invInfo = DateTimeFormatInfo.InvariantInfo;
1153 if (format.Length == 1)
1154 format = DateTimeUtils.GetStandardPattern (format [0], dfi, out useutc, out use_invariant);
1156 result = new DateTime (0);
1160 if ((style & DateTimeStyles.AllowLeadingWhite) != 0) {
1161 format = format.TrimStart (null);
1163 s = s.TrimStart (null); // it could be optimized, but will make little good.
1166 if ((style & DateTimeStyles.AllowTrailingWhite) != 0) {
1167 format = format.TrimEnd (null);
1168 s = s.TrimEnd (null); // it could be optimized, but will make little good.
1174 if ((style & DateTimeStyles.AllowInnerWhite) != 0)
1175 sloppy_parsing = true;
1177 string chars = format;
1178 int len = format.Length, pos = 0, num = 0;
1182 int day = -1, dayofweek = -1, month = -1, year = -1;
1183 int hour = -1, minute = -1, second = -1;
1184 double fractionalSeconds = -1;
1186 int tzsign = -1, tzoffset = -1, tzoffmin = -1;
1187 bool isFirstPart = true;
1191 if (valuePos == s.Length)
1195 if (flexibleTwoPartsParsing && pos + num == 0)
1197 bool isLetter = IsLetter(s, valuePos);
1199 if (s [valuePos] == 'Z')
1202 _ParseString (s, valuePos, 0, "GMT", out num_parsed);
1203 if (num_parsed > 0 && !IsLetter (s, valuePos + num_parsed)) {
1204 valuePos += num_parsed;
1209 if (!afterTFormat && _ParseAmPm (s, valuePos, 0, dfi, exact, out num_parsed, ref ampm)) {
1210 if (IsLetter (s, valuePos + num_parsed))
1212 else if (num_parsed > 0) {
1213 valuePos += num_parsed;
1218 if (!afterTFormat && dayofweek == -1 && isLetter) {
1219 dayofweek = _ParseEnum (s, valuePos, dfi.RawDayNames, invInfo.RawDayNames, exact, out num_parsed);
1220 if (dayofweek == -1)
1221 dayofweek = _ParseEnum (s, valuePos, dfi.RawAbbreviatedDayNames, invInfo.RawAbbreviatedDayNames, exact, out num_parsed);
1222 if (dayofweek != -1 && !IsLetter (s, valuePos + num_parsed)) {
1223 valuePos += num_parsed;
1230 if (char.IsWhiteSpace (s [valuePos]) || s [valuePos] == ',') {
1237 if (pos + num >= len)
1239 if (flexibleTwoPartsParsing && num == 0) {
1240 afterTFormat = isFirstPart && firstPart [firstPart.Length - 1] == 'T';
1241 if (!isFirstPart && format == "")
1246 format = secondPart;
1251 isFirstPart = false;
1257 bool leading_zeros = true;
1259 if (chars[pos] == '\'') {
1261 while (pos+num < len) {
1262 if (chars[pos+num] == '\'')
1265 if (valuePos == s.Length || s [valuePos] != chars [pos + num])
1275 } else if (chars[pos] == '"') {
1277 while (pos+num < len) {
1278 if (chars[pos+num] == '"')
1281 if (valuePos == s.Length || s [valuePos] != chars[pos+num])
1291 } else if (chars[pos] == '\\') {
1296 if (s [valuePos] != chars [pos])
1302 } else if (chars[pos] == '%') {
1305 } else if (char.IsWhiteSpace (s [valuePos]) ||
1306 s [valuePos] == ',' && (!exact && chars [pos] == '/' || Char.IsWhiteSpace (chars [pos]))) {
1309 if (exact && (style & DateTimeStyles.AllowInnerWhite) == 0) {
1310 if (!Char.IsWhiteSpace (chars[pos]))
1317 while (ws < s.Length) {
1318 if (Char.IsWhiteSpace (s [ws]) || s [ws] == ',')
1325 while (ws < chars.Length) {
1326 if (Char.IsWhiteSpace (chars [ws]) || chars [ws] == ',')
1332 // A whitespace may match a '/' in the pattern.
1333 if (!exact && pos < chars.Length && chars[pos] == '/')
1334 if (!_ParseDateSeparator (s, valuePos, dfi, exact, out num_parsed))
1339 if ((pos+num+1 < len) && (chars[pos+num+1] == chars[pos+num])) {
1347 if (num < 2 && day != -1 || num >= 2 && dayofweek != -1)
1350 day = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1352 day = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1354 dayofweek = _ParseEnum (s, valuePos, dfi.RawAbbreviatedDayNames, invInfo.RawAbbreviatedDayNames, exact, out num_parsed);
1356 dayofweek = _ParseEnum (s, valuePos, dfi.RawDayNames, invInfo.RawDayNames, exact, out num_parsed);
1362 if (flexibleTwoPartsParsing) {
1364 if (num == 0 || num == 3)
1365 month = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1366 if (num > 1 && num_parsed == -1)
1367 month = _ParseEnum (s, valuePos, dfi.RawMonthNames, invInfo.RawMonthNames, exact, out num_parsed) + 1;
1368 if (num > 1 && num_parsed == -1)
1369 month = _ParseEnum (s, valuePos, dfi.RawAbbreviatedMonthNames, invInfo.RawAbbreviatedMonthNames, exact, out num_parsed) + 1;
1374 month = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1376 month = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1378 month = _ParseEnum (s, valuePos, dfi.RawAbbreviatedMonthNames, invInfo.RawAbbreviatedMonthNames, exact, out num_parsed) + 1;
1380 month = _ParseEnum (s, valuePos, dfi.RawMonthNames, invInfo.RawMonthNames, exact, out num_parsed) + 1;
1387 year = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1388 } else if (num < 3) {
1389 year = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1391 year = _ParseNumber (s, valuePos, exact ? 4 : 3, 4, false, sloppy_parsing, out num_parsed);
1392 if ((year >= 1000) && (num_parsed == 4) && (!longYear) && (s.Length > 4 + valuePos)) {
1394 int ly = _ParseNumber (s, valuePos, 5, 5, false, sloppy_parsing, out np);
1395 longYear = (ly > 9999);
1400 //FIXME: We should do use dfi.Calendat.TwoDigitYearMax
1401 if (num_parsed <= 2)
1402 year += (year < 30) ? 2000 : 1900;
1408 hour = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1410 hour = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1419 if (hour != -1 || !flexibleTwoPartsParsing && ampm >= 0)
1422 hour = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1424 hour = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1435 minute = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1437 minute = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1447 second = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1449 second = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1456 leading_zeros = false;
1459 if (num > 6 || fractionalSeconds != -1)
1461 double decimalNumber = (double) _ParseNumber (s, valuePos, 0, num+1, leading_zeros, sloppy_parsing, out num_parsed);
1462 if (num_parsed == -1)
1464 fractionalSeconds = decimalNumber / Math.Pow(10.0, num_parsed);
1467 if (!_ParseAmPm (s, valuePos, num > 0 ? 0 : 1, dfi, exact, out num_parsed, ref ampm))
1474 if (s [valuePos] == '+')
1476 else if (s [valuePos] == '-')
1483 tzoffset = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1485 tzoffset = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1487 tzoffset = _ParseNumber (s, valuePos, 1, 2, true, /*sloppy_parsing*/true, out num_parsed);
1488 valuePos += num_parsed;
1493 if (valuePos < s.Length && Char.IsDigit (s [valuePos]) ||
1494 _ParseTimeSeparator (s, valuePos, dfi, exact, out num_parsed)) {
1495 valuePos += num_parsed;
1496 tzoffmin = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1500 else if (!flexibleTwoPartsParsing)
1507 if (s [valuePos] == 'Z') {
1511 else if (s [valuePos] == '+' || s [valuePos] == '-') {
1514 if (s [valuePos] == '+')
1516 else if (s [valuePos] == '-')
1521 tzoffset = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1522 valuePos += num_parsed;
1526 if (Char.IsDigit (s [valuePos]))
1528 else if (!_ParseString (s, valuePos, 0, dfi.TimeSeparator, out num_parsed))
1530 valuePos += num_parsed;
1532 tzoffmin = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1539 // LAMESPEC: This should be part of UTCpattern
1540 // string and thus should not be considered here.
1542 // Note that 'Z' is not defined as a pattern
1543 // character. Keep it for X509 certificate
1544 // verification. Also, "Z" != "'Z'" under MS.NET
1545 // ("'Z'" is just literal; handled above)
1547 if (s [valuePos] != 'Z')
1554 if (s [valuePos] != 'G')
1557 if ((pos + 2 < len) && (valuePos + 2 < s.Length) &&
1558 (chars [pos + 1] == 'M') && (s[valuePos + 1] == 'M') &&
1559 (chars [pos + 2] == 'T') && (s[valuePos + 2] == 'T'))
1571 if (!_ParseTimeSeparator (s, valuePos, dfi, exact, out num_parsed))
1575 if (!_ParseDateSeparator (s, valuePos, dfi, exact, out num_parsed))
1581 if (s [valuePos] != chars [pos])
1592 valuePos += num_parsed;
1594 if (!exact && !flexibleTwoPartsParsing) {
1595 switch (chars [pos]) {
1601 if (s.Length > valuePos && s [valuePos] == 'Z' &&
1602 (pos + 1 == chars.Length || chars [pos + 1] != 'Z')) {
1610 pos = pos + num + 1;
1614 if (pos + 1 < len && chars [pos] == '.' && chars [pos + 1] == 'F') {
1616 while (pos < len && chars [pos] == 'F') // '.FFF....' can be mapped to nothing. See bug #444103
1619 while (pos < len && chars [pos] == 'K') // 'K' can be mapped to nothing
1625 if (s.Length > valuePos) // extraneous tail.
1630 if (Char.IsDigit (s [valuePos]) && Char.IsDigit (s [valuePos - 1]))
1632 if (Char.IsLetter (s [valuePos]) && Char.IsLetter (s [valuePos - 1]))
1634 incompleteFormat = true;
1645 if (fractionalSeconds == -1)
1646 fractionalSeconds = 0;
1648 // If no date was given
1649 if ((day == -1) && (month == -1) && (year == -1)) {
1650 if ((style & DateTimeStyles.NoCurrentDateDefault) != 0) {
1655 day = DateTime.Today.Day;
1656 month = DateTime.Today.Month;
1657 year = DateTime.Today.Year;
1666 if ((style & DateTimeStyles.NoCurrentDateDefault) != 0)
1669 year = DateTime.Today.Year;
1672 if (ampm == 0 && hour == 12)
1675 if (ampm == 1 && (!flexibleTwoPartsParsing || hour < 12))
1678 // For anything out of range
1680 if (year < 1 || year > 9999 ||
1681 month < 1 || month >12 ||
1682 day < 1 || day > DateTime.DaysInMonth(year, month) ||
1683 hour < 0 || hour > 23 ||
1684 minute < 0 || minute > 59 ||
1685 second < 0 || second > 59)
1688 result = new DateTime (year, month, day, hour, minute, second, 0);
1689 result = result.AddSeconds(fractionalSeconds);
1691 if (dayofweek != -1 && dayofweek != (int) result.DayOfWeek)
1695 if (result != DateTime.MinValue) {
1697 dto = new DateTimeOffset (result);
1698 } catch { } // We handle this error in DateTimeOffset.Parse
1706 tzoffset = -tzoffset;
1707 tzoffmin = -tzoffmin;
1710 dto = new DateTimeOffset (result, new TimeSpan (tzoffset, tzoffmin, 0));
1711 } catch {} // We handle this error in DateTimeOffset.Parse
1713 bool adjustToUniversal = (style & DateTimeStyles.AdjustToUniversal) != 0;
1716 long newticks = (result.ticks - dto.Offset).Ticks;
1718 newticks += TimeSpan.TicksPerDay;
1719 result = new DateTime (false, new TimeSpan (newticks));
1720 result.kind = DateTimeKind.Utc;
1721 if ((style & DateTimeStyles.RoundtripKind) != 0)
1722 result = result.ToLocalTime ();
1724 else if (useutc || ((style & DateTimeStyles.AssumeUniversal) != 0))
1725 result.kind = DateTimeKind.Utc;
1726 else if ((style & DateTimeStyles.AssumeLocal) != 0)
1727 result.kind = DateTimeKind.Local;
1729 bool adjustToLocal = !adjustToUniversal && (style & DateTimeStyles.RoundtripKind) == 0;
1730 if (result.kind != DateTimeKind.Unspecified)
1732 if (adjustToUniversal)
1733 result = result.ToUniversalTime ();
1734 else if (adjustToLocal)
1735 result = result.ToLocalTime ();
1740 public static DateTime ParseExact (string s, string format,
1741 IFormatProvider provider, DateTimeStyles style)
1744 throw new ArgumentNullException ("format");
1746 string [] formats = new string [1];
1747 formats[0] = format;
1749 return ParseExact (s, formats, provider, style);
1752 public static DateTime ParseExact (string s, string[] formats,
1753 IFormatProvider provider,
1754 DateTimeStyles style)
1756 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
1759 throw new ArgumentNullException ("s");
1760 if (formats == null)
1761 throw new ArgumentNullException ("formats");
1762 if (formats.Length == 0)
1763 throw new FormatException ("Format specifier was invalid.");
1766 bool longYear = false;
1768 if (!ParseExact (s, formats, dfi, style, out result, true, ref longYear, true, ref e))
1773 private static void CheckStyle (DateTimeStyles style)
1775 if ( (style & DateTimeStyles.RoundtripKind) != 0)
1777 if ((style & DateTimeStyles.AdjustToUniversal) != 0 || (style & DateTimeStyles.AssumeLocal) != 0 ||
1778 (style & DateTimeStyles.AssumeUniversal) != 0)
1779 throw new ArgumentException ("The DateTimeStyles value RoundtripKind cannot be used with the values AssumeLocal, Asersal or AdjustToUniversal.", "style");
1781 if ((style & DateTimeStyles.AssumeUniversal) != 0 && (style & DateTimeStyles.AssumeLocal) != 0)
1782 throw new ArgumentException ("The DateTimeStyles values AssumeLocal and AssumeUniversal cannot be used together.", "style");
1785 public static bool TryParse (string s, out DateTime result)
1789 Exception exception = null;
1792 return CoreParse (s, null, DateTimeStyles.AllowWhiteSpaces, out result, out dto, false, ref exception);
1799 public static bool TryParse (string s, IFormatProvider provider, DateTimeStyles styles, out DateTime result)
1803 Exception exception = null;
1806 return CoreParse (s, provider, styles, out result, out dto, false, ref exception);
1813 public static bool TryParseExact (string s, string format,
1814 IFormatProvider provider,
1815 DateTimeStyles style,
1816 out DateTime result)
1819 formats = new string [1];
1820 formats[0] = format;
1822 return TryParseExact (s, formats, provider, style, out result);
1825 public static bool TryParseExact (string s, string[] formats,
1826 IFormatProvider provider,
1827 DateTimeStyles style,
1828 out DateTime result)
1830 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
1832 bool longYear = false;
1834 return ParseExact (s, formats, dfi, style, out result, true, ref longYear, false, ref e);
1837 private static bool ParseExact (string s, string [] formats,
1838 DateTimeFormatInfo dfi, DateTimeStyles style, out DateTime ret,
1839 bool exact, ref bool longYear,
1840 bool setExceptionOnError, ref Exception exception)
1843 bool incompleteFormat = false;
1844 for (i = 0; i < formats.Length; i++)
1847 string format = formats[i];
1848 if (format == null || format == String.Empty)
1852 if (_DoParse (s, formats[i], null, exact, out result, out dto, dfi, style, false, ref incompleteFormat, ref longYear)) {
1858 if (setExceptionOnError)
1859 exception = new FormatException ("Invalid format string");
1860 ret = DateTime.MinValue;
1864 public TimeSpan Subtract (DateTime value)
1866 return new TimeSpan (ticks.Ticks) - value.ticks;
1869 public DateTime Subtract(TimeSpan value)
1873 newticks = (new TimeSpan (ticks.Ticks)) - value;
1874 DateTime ret = new DateTime (true,newticks);
1879 public long ToFileTime()
1881 DateTime universalTime = ToUniversalTime();
1883 if (universalTime.Ticks < w32file_epoch) {
1884 throw new ArgumentOutOfRangeException("file time is not valid");
1887 return(universalTime.Ticks - w32file_epoch);
1890 public long ToFileTimeUtc()
1892 if (Ticks < w32file_epoch) {
1893 throw new ArgumentOutOfRangeException("file time is not valid");
1896 return (Ticks - w32file_epoch);
1899 public string ToLongDateString()
1901 return ToString ("D");
1904 public string ToLongTimeString()
1906 return ToString ("T");
1909 public double ToOADate ()
1911 long t = this.Ticks;
1912 // uninitialized DateTime case
1915 // we can't reach minimum value
1916 if (t < 31242239136000000)
1917 return OAMinValue + 0.001;
1919 TimeSpan ts = new TimeSpan (this.Ticks - ticks18991230);
1920 double result = ts.TotalDays;
1921 // t < 0 (where 599264352000000000 == 0.0d for OA)
1922 if (t < 599264352000000000) {
1923 // negative days (int) but decimals are positive
1924 double d = Math.Ceiling (result);
1925 result = d - 2 - (result - d);
1928 // we can't reach maximum value
1929 if (result >= OAMaxValue)
1930 result = OAMaxValue - 0.00000001d;
1935 public string ToShortDateString()
1937 return ToString ("d");
1940 public string ToShortTimeString()
1942 return ToString ("t");
1945 public override string ToString ()
1947 return ToString ("G", null);
1950 public string ToString (IFormatProvider provider)
1952 return ToString (null, provider);
1955 public string ToString (string format)
1957 return ToString (format, null);
1960 public string ToString (string format, IFormatProvider provider)
1962 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
1964 if (format == null || format == String.Empty)
1967 bool useutc = false, use_invariant = false;
1969 if (format.Length == 1) {
1970 char fchar = format [0];
1971 format = DateTimeUtils.GetStandardPattern (fchar, dfi, out useutc, out use_invariant);
1973 return DateTimeUtils.ToString (ToUniversalTime (), format, dfi);
1974 // return ToUniversalTime()._ToString (format, dfi);
1977 throw new FormatException ("format is not one of the format specifier characters defined for DateTimeFormatInfo");
1980 // Don't convert UTC value. It just adds 'Z' for
1981 // 'u' format, for the same ticks.
1982 return DateTimeUtils.ToString (this, format, dfi);
1985 public DateTime ToLocalTime ()
1987 return TimeZone.CurrentTimeZone.ToLocalTime (this);
1990 public DateTime ToUniversalTime()
1992 return TimeZone.CurrentTimeZone.ToUniversalTime (this);
1997 public static DateTime operator +(DateTime d, TimeSpan t)
1999 DateTime ret = new DateTime (true, d.ticks + t);
2004 public static bool operator ==(DateTime d1, DateTime d2)
2006 return (d1.ticks == d2.ticks);
2009 public static bool operator >(DateTime t1,DateTime t2)
2011 return (t1.ticks > t2.ticks);
2014 public static bool operator >=(DateTime t1,DateTime t2)
2016 return (t1.ticks >= t2.ticks);
2019 public static bool operator !=(DateTime d1, DateTime d2)
2021 return (d1.ticks != d2.ticks);
2024 public static bool operator <(DateTime t1, DateTime t2)
2026 return (t1.ticks < t2.ticks );
2029 public static bool operator <=(DateTime t1,DateTime t2)
2031 return (t1.ticks <= t2.ticks);
2034 public static TimeSpan operator -(DateTime d1,DateTime d2)
2036 return new TimeSpan((d1.ticks - d2.ticks).Ticks);
2039 public static DateTime operator -(DateTime d,TimeSpan t)
2041 DateTime ret = new DateTime (true, d.ticks - t);
2046 bool IConvertible.ToBoolean(IFormatProvider provider)
2048 throw new InvalidCastException();
2051 byte IConvertible.ToByte(IFormatProvider provider)
2053 throw new InvalidCastException();
2057 char IConvertible.ToChar(IFormatProvider provider)
2059 throw new InvalidCastException();
2062 System.DateTime IConvertible.ToDateTime(IFormatProvider provider)
2067 decimal IConvertible.ToDecimal(IFormatProvider provider)
2069 throw new InvalidCastException();
2072 double IConvertible.ToDouble(IFormatProvider provider)
2074 throw new InvalidCastException();
2077 Int16 IConvertible.ToInt16(IFormatProvider provider)
2079 throw new InvalidCastException();
2082 Int32 IConvertible.ToInt32(IFormatProvider provider)
2084 throw new InvalidCastException();
2087 Int64 IConvertible.ToInt64(IFormatProvider provider)
2089 throw new InvalidCastException();
2092 SByte IConvertible.ToSByte(IFormatProvider provider)
2094 throw new InvalidCastException();
2097 Single IConvertible.ToSingle(IFormatProvider provider)
2099 throw new InvalidCastException();
2102 object IConvertible.ToType (Type targetType, IFormatProvider provider)
2104 if (targetType == null)
2105 throw new ArgumentNullException ("targetType");
2107 if (targetType == typeof (DateTime))
2109 else if (targetType == typeof (String))
2110 return this.ToString (provider);
2111 else if (targetType == typeof (Object))
2114 throw new InvalidCastException();
2117 UInt16 IConvertible.ToUInt16(IFormatProvider provider)
2119 throw new InvalidCastException();
2122 UInt32 IConvertible.ToUInt32(IFormatProvider provider)
2124 throw new InvalidCastException();
2127 UInt64 IConvertible.ToUInt64(IFormatProvider provider)
2129 throw new InvalidCastException();