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 value)
547 DateTime ret = AddTicks (value.Ticks);
554 public DateTime AddDays (double value)
556 return AddMilliseconds (Math.Round (value * 86400000));
559 public DateTime AddTicks (long value)
561 if ((value + ticks.Ticks) > MAX_VALUE_TICKS || (value + ticks.Ticks) < 0) {
562 throw new ArgumentOutOfRangeException();
564 DateTime ret = new DateTime (value + ticks.Ticks);
571 public DateTime AddHours (double value)
573 return AddMilliseconds (value * 3600000);
576 public DateTime AddMilliseconds (double value)
578 if ((value * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
579 (value * TimeSpan.TicksPerMillisecond) < long.MinValue) {
580 throw new ArgumentOutOfRangeException();
582 long msticks = (long) (value * 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 value)
601 return AddMilliseconds (value * 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 value)
636 return AddMilliseconds (value * 1000);
639 public DateTime AddYears (int value)
641 return AddMonths (value * 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 value)
659 if (!(value is System.DateTime))
660 throw new ArgumentException (Locale.GetText (
661 "Value is not a System.DateTime"));
663 return Compare (this, (DateTime) value);
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 value)
742 if (!(value is System.DateTime))
745 return ((DateTime) value).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 provider)
883 return Parse (s, provider, DateTimeStyles.AllowWhiteSpaces);
886 public static DateTime Parse (string s, IFormatProvider provider, DateTimeStyles styles)
889 throw new ArgumentNullException ("s");
892 Exception exception = null;
893 if (!CoreParse (s, provider, styles, out res, true, ref exception))
899 const string formatExceptionMessage = "String was not recognized as a valid DateTime.";
901 internal static bool CoreParse (string s, IFormatProvider provider, DateTimeStyles styles,
902 out DateTime result, bool setExceptionOnError, ref Exception exception)
904 if (s == null || s.Length == 0) {
905 if (setExceptionOnError)
906 exception = new FormatException (formatExceptionMessage);
911 if (provider == null)
912 provider = CultureInfo.CurrentCulture;
913 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
915 // Try first all the combinations of ParseAllDateFormats & ParseTimeFormats
916 string[] allDateFormats = YearMonthDayFormats (dfi, setExceptionOnError, ref exception);
917 if (allDateFormats == null){
922 bool longYear = false;
923 for (int i = 0; i < allDateFormats.Length; i++) {
924 string firstPart = allDateFormats [i];
925 bool incompleteFormat = false;
926 if (_DoParse (s, firstPart, "", false, out result, dfi, styles, true, ref incompleteFormat, ref longYear))
929 if (!incompleteFormat)
932 for (int j = 0; j < ParseTimeFormats.Length; j++) {
933 if (_DoParse (s, firstPart, ParseTimeFormats [j], false, out result, dfi, styles, true, ref incompleteFormat, ref longYear))
941 int dayIndex = dfi.MonthDayPattern.IndexOf('d');
942 int monthIndex = dfi.MonthDayPattern.IndexOf('M');
943 if (dayIndex == -1 || monthIndex == -1){
945 if (setExceptionOnError)
946 exception = new FormatException (Locale.GetText("Order of month and date is not defined by {0}", dfi.MonthDayPattern));
949 bool is_day_before_month = dayIndex < monthIndex;
950 string[] monthDayFormats = is_day_before_month ? DayMonthShortFormats : MonthDayShortFormats;
951 for (int i = 0; i < monthDayFormats.Length; i++) {
952 bool incompleteFormat = false;
953 if (_DoParse (s, monthDayFormats[i], "", false, out result, dfi, styles, true, ref incompleteFormat, ref longYear))
957 for (int j = 0; j < ParseTimeFormats.Length; j++) {
958 string firstPart = ParseTimeFormats [j];
959 bool incompleteFormat = false;
960 if (_DoParse (s, firstPart, "", false, out result, dfi, styles, false, ref incompleteFormat, ref longYear))
962 if (!incompleteFormat)
965 for (int i = 0; i < monthDayFormats.Length; i++) {
966 if (_DoParse (s, firstPart, monthDayFormats [i], false, out result, dfi, styles, false, ref incompleteFormat, ref longYear))
969 for (int i = 0; i < allDateFormats.Length; i++) {
970 string dateFormat = allDateFormats [i];
971 if (dateFormat[dateFormat.Length - 1] == 'T')
972 continue; // T formats must be before the time part
973 if (_DoParse (s, firstPart, dateFormat, false, out result, dfi, styles, false, ref incompleteFormat, ref longYear))
978 // Try as a last resort all the patterns
979 if (ParseExact (s, dfi.GetAllDateTimePatternsInternal (), dfi, styles, out result, false, ref longYear, setExceptionOnError, ref exception))
982 if (!setExceptionOnError)
986 // .NET 2.x does not throw an ArgumentOutOfRangeException, but .NET 1.1 does.
987 exception = new FormatException (formatExceptionMessage);
990 exception = new ArgumentOutOfRangeException ("year", "Valid values are between 1 and 9999, inclusive.");
992 exception = new FormatException (formatExceptionMessage);
997 public static DateTime ParseExact (string s, string format, IFormatProvider provider)
999 return ParseExact (s, format, provider, DateTimeStyles.None);
1002 private static string[] YearMonthDayFormats (DateTimeFormatInfo dfi, bool setExceptionOnError, ref Exception exc)
1004 int dayIndex = dfi.ShortDatePattern.IndexOf('d');
1005 int monthIndex = dfi.ShortDatePattern.IndexOf('M');
1006 int yearIndex = dfi.ShortDatePattern.IndexOf('y');
1007 if (dayIndex == -1 || monthIndex == -1 || yearIndex == -1){
1008 if (setExceptionOnError)
1009 exc = new FormatException (Locale.GetText("Order of year, month and date is not defined by {0}", dfi.ShortDatePattern));
1013 if (yearIndex < monthIndex)
1014 if (monthIndex < dayIndex)
1015 return ParseYearMonthDayFormats;
1016 else if (yearIndex < dayIndex)
1017 return ParseYearDayMonthFormats;
1019 // The year cannot be between the date and the month
1020 if (setExceptionOnError)
1021 exc = new FormatException (Locale.GetText("Order of date, year and month defined by {0} is not supported", dfi.ShortDatePattern));
1024 else if (dayIndex < monthIndex)
1025 return ParseDayMonthYearFormats;
1026 else if (dayIndex < yearIndex)
1027 return ParseMonthDayYearFormats;
1029 // The year cannot be between the month and the date
1030 if (setExceptionOnError)
1031 exc = new FormatException (Locale.GetText("Order of month, year and date defined by {0} is not supported", dfi.ShortDatePattern));
1036 private static int _ParseNumber (string s, int valuePos,
1040 bool sloppy_parsing,
1046 leadingzero = false;
1049 int real_digits = 0;
1050 for (i = valuePos; i < s.Length && i < digits + valuePos; i++) {
1051 if (!Char.IsDigit (s[i]))
1057 digits = real_digits;
1059 if (digits < min_digits) {
1064 if (s.Length - valuePos < digits) {
1069 for (i = valuePos; i < digits + valuePos; i++) {
1071 if (!Char.IsDigit (c)) {
1076 number = number * 10 + (byte) (c - '0');
1079 num_parsed = digits;
1083 private static int _ParseEnum (string s, int sPos, string[] values, string[] invValues, bool exact, out int num_parsed)
1085 // FIXME: I know this is somehow lame code. Probably
1086 // it should iterate all the enum value and return
1087 // the longest match. However right now I don't see
1088 // anything but "1" and "10" - "12" that might match
1089 // two or more values. (They are only abbrev month
1090 // names, so do reverse order search). See bug #80094.
1091 for (int i = values.Length - 1; i >= 0; i--) {
1092 if (!exact && invValues [i].Length > values[i].Length) {
1093 if (invValues [i].Length > 0 && _ParseString (s, sPos, 0, invValues [i], out num_parsed))
1095 if (values [i].Length > 0 && _ParseString (s, sPos, 0, values [i], out num_parsed))
1099 if (values [i].Length > 0 && _ParseString (s, sPos, 0, values [i], out num_parsed))
1101 if (!exact && invValues [i].Length > 0 && _ParseString (s, sPos, 0, invValues [i], out num_parsed))
1110 private static bool _ParseString (string s, int sPos, int maxlength, string value, out int num_parsed)
1113 maxlength = value.Length;
1115 if (sPos + maxlength <= s.Length && String.Compare (s, sPos, value, 0, maxlength, true, CultureInfo.InvariantCulture) == 0) {
1116 num_parsed = maxlength;
1124 // Note that in case of Parse (exact == false) we check both for AM/PM
1125 // and the culture spcific AM/PM strings.
1126 private static bool _ParseAmPm(string s,
1129 DateTimeFormatInfo dfi,
1138 if (!IsLetter (s, valuePos)) {
1139 if (dfi.AMDesignator != "")
1146 DateTimeFormatInfo invInfo = DateTimeFormatInfo.InvariantInfo;
1147 if (!exact && _ParseString (s, valuePos, num, invInfo.PMDesignator, out num_parsed) ||
1148 dfi.PMDesignator != "" && _ParseString(s, valuePos, num, dfi.PMDesignator, out num_parsed))
1150 else if (!exact && _ParseString (s, valuePos, num, invInfo.AMDesignator, out num_parsed) ||
1151 _ParseString (s, valuePos, num, dfi.AMDesignator, out num_parsed)) {
1152 if (exact || num_parsed != 0)
1160 // Note that in case of Parse (exact == false) we check both for ':'
1161 // and the culture spcific TimeSperator
1162 private static bool _ParseTimeSeparator (string s, int sPos, DateTimeFormatInfo dfi, bool exact, out int num_parsed)
1164 return _ParseString (s, sPos, 0, dfi.TimeSeparator, out num_parsed) ||
1165 !exact && _ParseString (s, sPos, 0, ":", out num_parsed);
1168 // Accept any character for DateSeparator, except TimeSeparator,
1169 // a digit or a letter.
1170 // Not documented, but seems to be MS behaviour here. See bug 54047.
1171 private static bool _ParseDateSeparator (string s, int sPos, DateTimeFormatInfo dfi, bool exact, out int num_parsed)
1174 if (exact && s [sPos] != '/')
1177 if (_ParseTimeSeparator (s, sPos, dfi, exact, out num_parsed) ||
1178 Char.IsDigit (s [sPos]) || Char.IsLetter (s [sPos]))
1185 private static bool IsLetter (string s, int pos)
1187 return pos < s.Length && Char.IsLetter (s [pos]);
1190 // To implement better DateTime.Parse we use two format strings one
1191 // for Date and one for Time. This allows us to define two different
1192 // arrays of formats for Time and Dates and to combine them more or less
1193 // efficiently. When this mode is used flexibleTwoPartsParsing is true.
1194 private static bool _DoParse (string s,
1198 out DateTime result,
1199 DateTimeFormatInfo dfi,
1200 DateTimeStyles style,
1201 bool firstPartIsDate,
1202 ref bool incompleteFormat,
1205 bool useutc = false;
1206 bool use_invariant = false;
1207 bool sloppy_parsing = false;
1209 bool afterTimePart = firstPartIsDate && secondPart == "";
1211 bool flexibleTwoPartsParsing = !exact && secondPart != null;
1212 incompleteFormat = false;
1214 string format = firstPart;
1215 bool afterTFormat = false;
1216 DateTimeFormatInfo invInfo = DateTimeFormatInfo.InvariantInfo;
1217 if (format.Length == 1)
1218 format = DateTimeUtils.GetStandardPattern (format [0], dfi, out useutc, out use_invariant);
1220 result = new DateTime (0);
1224 if ((style & DateTimeStyles.AllowLeadingWhite) != 0) {
1225 format = format.TrimStart (null);
1227 s = s.TrimStart (null); // it could be optimized, but will make little good.
1230 if ((style & DateTimeStyles.AllowTrailingWhite) != 0) {
1231 format = format.TrimEnd (null);
1232 s = s.TrimEnd (null); // it could be optimized, but will make little good.
1238 if ((style & DateTimeStyles.AllowInnerWhite) != 0)
1239 sloppy_parsing = true;
1241 string chars = format;
1242 int len = format.Length, pos = 0, num = 0;
1246 int day = -1, dayofweek = -1, month = -1, year = -1;
1247 int hour = -1, minute = -1, second = -1;
1248 double fractionalSeconds = -1;
1250 int tzsign = -1, tzoffset = -1, tzoffmin = -1;
1251 bool isFirstPart = true;
1255 if (valuePos == s.Length)
1259 if (flexibleTwoPartsParsing && pos + num == 0)
1261 bool isLetter = IsLetter(s, valuePos);
1265 if (afterTimePart && isLetter) {
1267 if (s [valuePos] == 'Z')
1270 _ParseString (s, valuePos, 0, "GMT", out num_parsed);
1271 if (num_parsed > 0 && !IsLetter (s, valuePos + num_parsed)) {
1272 valuePos += num_parsed;
1277 if (!afterTFormat && _ParseAmPm (s, valuePos, 0, dfi, exact, out num_parsed, ref ampm)) {
1278 if (IsLetter (s, valuePos + num_parsed))
1280 else if (num_parsed > 0) {
1281 valuePos += num_parsed;
1286 if (!afterTFormat && dayofweek == -1 && isLetter) {
1287 dayofweek = _ParseEnum (s, valuePos, dfi.RawDayNames, invInfo.RawDayNames, exact, out num_parsed);
1288 if (dayofweek == -1)
1289 dayofweek = _ParseEnum (s, valuePos, dfi.RawAbbreviatedDayNames, invInfo.RawAbbreviatedDayNames, exact, out num_parsed);
1290 if (dayofweek != -1 && !IsLetter (s, valuePos + num_parsed)) {
1291 valuePos += num_parsed;
1298 if (char.IsWhiteSpace (s [valuePos]) || s [valuePos] == ',') {
1305 if (pos + num >= len)
1307 if (flexibleTwoPartsParsing && num == 0) {
1308 afterTFormat = isFirstPart && firstPart [firstPart.Length - 1] == 'T';
1309 if (!isFirstPart && format == "")
1314 format = secondPart;
1319 isFirstPart = false;
1321 if (!firstPartIsDate || format == "")
1322 afterTimePart = true;
1329 bool leading_zeros = true;
1331 if (chars[pos] == '\'') {
1333 while (pos+num < len) {
1334 if (chars[pos+num] == '\'')
1337 if (valuePos == s.Length || s [valuePos] != chars [pos + num])
1347 } else if (chars[pos] == '"') {
1349 while (pos+num < len) {
1350 if (chars[pos+num] == '"')
1353 if (valuePos == s.Length || s [valuePos] != chars[pos+num])
1363 } else if (chars[pos] == '\\') {
1368 if (s [valuePos] != chars [pos])
1374 } else if (chars[pos] == '%') {
1377 } else if (char.IsWhiteSpace (s [valuePos]) ||
1378 s [valuePos] == ',' && (!exact && chars [pos] == '/' || Char.IsWhiteSpace (chars [pos]))) {
1381 if (exact && (style & DateTimeStyles.AllowInnerWhite) == 0) {
1382 if (!Char.IsWhiteSpace (chars[pos]))
1389 while (ws < s.Length) {
1390 if (Char.IsWhiteSpace (s [ws]) || s [ws] == ',')
1397 while (ws < chars.Length) {
1398 if (Char.IsWhiteSpace (chars [ws]) || chars [ws] == ',')
1404 // A whitespace may match a '/' in the pattern.
1405 if (!exact && pos < chars.Length && chars[pos] == '/')
1406 if (!_ParseDateSeparator (s, valuePos, dfi, exact, out num_parsed))
1411 if ((pos+num+1 < len) && (chars[pos+num+1] == chars[pos+num])) {
1419 if (num < 2 && day != -1 || num >= 2 && dayofweek != -1)
1422 day = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1424 day = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1426 dayofweek = _ParseEnum (s, valuePos, dfi.RawAbbreviatedDayNames, invInfo.RawAbbreviatedDayNames, exact, out num_parsed);
1428 dayofweek = _ParseEnum (s, valuePos, dfi.RawDayNames, invInfo.RawDayNames, exact, out num_parsed);
1434 if (flexibleTwoPartsParsing) {
1436 if (num == 0 || num == 3)
1437 month = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1438 if (num > 1 && num_parsed == -1)
1439 month = _ParseEnum (s, valuePos, dfi.RawMonthNames, invInfo.RawMonthNames, exact, out num_parsed) + 1;
1440 if (num > 1 && num_parsed == -1)
1441 month = _ParseEnum (s, valuePos, dfi.RawAbbreviatedMonthNames, invInfo.RawAbbreviatedMonthNames, exact, out num_parsed) + 1;
1446 month = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1448 month = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1450 month = _ParseEnum (s, valuePos, dfi.RawAbbreviatedMonthNames, invInfo.RawAbbreviatedMonthNames, exact, out num_parsed) + 1;
1452 month = _ParseEnum (s, valuePos, dfi.RawMonthNames, invInfo.RawMonthNames, exact, out num_parsed) + 1;
1459 year = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1460 } else if (num < 3) {
1461 year = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1463 year = _ParseNumber (s, valuePos, exact ? 4 : 3, 4, false, sloppy_parsing, out num_parsed);
1464 if ((year >= 1000) && (num_parsed == 4) && (!longYear) && (s.Length > 4 + valuePos)) {
1466 int ly = _ParseNumber (s, valuePos, 5, 5, false, sloppy_parsing, out np);
1467 longYear = (ly > 9999);
1472 //FIXME: We should do use dfi.Calendat.TwoDigitYearMax
1473 if (num_parsed <= 2)
1474 year += (year < 30) ? 2000 : 1900;
1480 hour = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1482 hour = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1491 if (hour != -1 || !flexibleTwoPartsParsing && ampm >= 0)
1494 hour = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1496 hour = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1507 minute = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1509 minute = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1519 second = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1521 second = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1529 leading_zeros = false;
1533 if (num > 6 || fractionalSeconds != -1)
1535 double decimalNumber = (double) _ParseNumber (s, valuePos, 0, num+1, leading_zeros, sloppy_parsing, out num_parsed);
1536 if (num_parsed == -1)
1538 fractionalSeconds = decimalNumber / Math.Pow(10.0, num_parsed);
1541 if (!_ParseAmPm (s, valuePos, num > 0 ? 0 : 1, dfi, exact, out num_parsed, ref ampm))
1548 if (s [valuePos] == '+')
1550 else if (s [valuePos] == '-')
1557 tzoffset = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1559 tzoffset = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1561 tzoffset = _ParseNumber (s, valuePos, 1, 2, true, /*sloppy_parsing*/true, out num_parsed);
1562 valuePos += num_parsed;
1567 if (valuePos < s.Length && Char.IsDigit (s [valuePos]) ||
1568 _ParseTimeSeparator (s, valuePos, dfi, exact, out num_parsed)) {
1569 valuePos += num_parsed;
1570 tzoffmin = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1574 else if (!flexibleTwoPartsParsing)
1582 if (s [valuePos] == 'Z') {
1586 else if (s [valuePos] == '+' || s [valuePos] == '-') {
1589 if (s [valuePos] == '+')
1591 else if (s [valuePos] == '-')
1596 tzoffset = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1597 valuePos += num_parsed;
1601 if (Char.IsDigit (s [valuePos]))
1603 else if (!_ParseString (s, valuePos, 0, dfi.TimeSeparator, out num_parsed))
1605 valuePos += num_parsed;
1607 tzoffmin = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1614 // LAMESPEC: This should be part of UTCpattern
1615 // string and thus should not be considered here.
1617 // Note that 'Z' is not defined as a pattern
1618 // character. Keep it for X509 certificate
1619 // verification. Also, "Z" != "'Z'" under MS.NET
1620 // ("'Z'" is just literal; handled above)
1622 if (s [valuePos] != 'Z')
1629 if (s [valuePos] != 'G')
1632 if ((pos + 2 < len) && (valuePos + 2 < s.Length) &&
1633 (chars [pos + 1] == 'M') && (s[valuePos + 1] == 'M') &&
1634 (chars [pos + 2] == 'T') && (s[valuePos + 2] == 'T'))
1646 if (!_ParseTimeSeparator (s, valuePos, dfi, exact, out num_parsed))
1650 if (!_ParseDateSeparator (s, valuePos, dfi, exact, out num_parsed))
1656 if (s [valuePos] != chars [pos])
1667 valuePos += num_parsed;
1669 if (!exact && !flexibleTwoPartsParsing) {
1670 switch (chars [pos]) {
1678 if (s.Length > valuePos && s [valuePos] == 'Z' &&
1679 (pos + 1 == chars.Length || chars [pos + 1] != 'Z')) {
1687 pos = pos + num + 1;
1692 if (pos + 1 < len && chars [pos] == '.' && chars [pos + 1] == 'F') {
1694 while (pos < len && chars [pos] == 'F') // '.FFF....' can be mapped to nothing. See bug #444103
1697 while (pos < len && chars [pos] == 'K') // 'K' can be mapped to nothing
1703 if (s.Length > valuePos) // extraneous tail.
1708 if (Char.IsDigit (s [valuePos]) && Char.IsDigit (s [valuePos - 1]))
1710 if (Char.IsLetter (s [valuePos]) && Char.IsLetter (s [valuePos - 1]))
1712 incompleteFormat = true;
1723 if (fractionalSeconds == -1)
1724 fractionalSeconds = 0;
1726 // If no date was given
1727 if ((day == -1) && (month == -1) && (year == -1)) {
1728 if ((style & DateTimeStyles.NoCurrentDateDefault) != 0) {
1733 day = DateTime.Today.Day;
1734 month = DateTime.Today.Month;
1735 year = DateTime.Today.Year;
1744 if ((style & DateTimeStyles.NoCurrentDateDefault) != 0)
1747 year = DateTime.Today.Year;
1750 if (ampm == 0 && hour == 12)
1753 if (ampm == 1 && (!flexibleTwoPartsParsing || hour < 12))
1756 // For anything out of range
1758 if (year < 1 || year > 9999 ||
1759 month < 1 || month >12 ||
1760 day < 1 || day > DateTime.DaysInMonth(year, month) ||
1761 hour < 0 || hour > 23 ||
1762 minute < 0 || minute > 59 ||
1763 second < 0 || second > 59)
1766 result = new DateTime (year, month, day, hour, minute, second, 0);
1767 result = result.AddSeconds(fractionalSeconds);
1769 if (dayofweek != -1 && dayofweek != (int) result.DayOfWeek)
1774 bool adjustToUniversal = (style & DateTimeStyles.AdjustToUniversal) != 0;
1782 tzoffset = -tzoffset;
1784 utcoffset = new TimeSpan (tzoffset, tzoffmin, 0);
1785 long newticks = (result.ticks - utcoffset).Ticks;
1787 newticks += TimeSpan.TicksPerDay;
1788 result = new DateTime (false, new TimeSpan (newticks));
1790 result.kind = DateTimeKind.Utc;
1791 if ((style & DateTimeStyles.RoundtripKind) != 0)
1792 result = result.ToLocalTime ();
1796 else if (useutc || ((style & DateTimeStyles.AssumeUniversal) != 0))
1797 result.kind = DateTimeKind.Utc;
1798 else if ((style & DateTimeStyles.AssumeLocal) != 0)
1799 result.kind = DateTimeKind.Local;
1801 bool adjustToLocal = !adjustToUniversal && (style & DateTimeStyles.RoundtripKind) == 0;
1802 if (result.kind != DateTimeKind.Unspecified)
1804 if (adjustToUniversal)
1805 result = result.ToUniversalTime ();
1806 else if (adjustToLocal)
1807 result = result.ToLocalTime ();
1810 if (!adjustToUniversal && (useutc || tzsign != -1))
1811 result = result.ToLocalTime ();
1816 public static DateTime ParseExact (string s, string format,
1817 IFormatProvider provider, DateTimeStyles style)
1820 throw new ArgumentNullException ("format");
1822 string [] formats = new string [1];
1823 formats[0] = format;
1825 return ParseExact (s, formats, provider, style);
1828 public static DateTime ParseExact (string s, string[] formats,
1829 IFormatProvider provider,
1830 DateTimeStyles style)
1832 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
1837 throw new ArgumentNullException ("s");
1838 if (formats == null)
1839 throw new ArgumentNullException ("formats");
1840 if (formats.Length == 0)
1841 throw new FormatException ("Format specifier was invalid.");
1844 bool longYear = false;
1846 if (!ParseExact (s, formats, dfi, style, out result, true, ref longYear, true, ref e))
1852 private static void CheckStyle (DateTimeStyles style)
1854 if ( (style & DateTimeStyles.RoundtripKind) != 0)
1856 if ((style & DateTimeStyles.AdjustToUniversal) != 0 || (style & DateTimeStyles.AssumeLocal) != 0 ||
1857 (style & DateTimeStyles.AssumeUniversal) != 0)
1858 throw new ArgumentException ("The DateTimeStyles value RoundtripKind cannot be used with the values AssumeLocal, Asersal or AdjustToUniversal.", "style");
1860 if ((style & DateTimeStyles.AssumeUniversal) != 0 && (style & DateTimeStyles.AssumeLocal) != 0)
1861 throw new ArgumentException ("The DateTimeStyles values AssumeLocal and AssumeUniversal cannot be used together.", "style");
1864 public static bool TryParse (string s, out DateTime result)
1868 Exception exception = null;
1870 return CoreParse (s, null, DateTimeStyles.AllowWhiteSpaces, out result, false, ref exception);
1877 public static bool TryParse (string s, IFormatProvider provider, DateTimeStyles styles, out DateTime result)
1881 Exception exception = null;
1883 return CoreParse (s, provider, styles, out result, false, ref exception);
1890 public static bool TryParseExact (string s, string format,
1891 IFormatProvider provider,
1892 DateTimeStyles style,
1893 out DateTime result)
1896 formats = new string [1];
1897 formats[0] = format;
1899 return TryParseExact (s, formats, provider, style, out result);
1902 public static bool TryParseExact (string s, string[] formats,
1903 IFormatProvider provider,
1904 DateTimeStyles style,
1905 out DateTime result)
1907 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
1909 bool longYear = false;
1911 return ParseExact (s, formats, dfi, style, out result, true, ref longYear, false, ref e);
1915 private static bool ParseExact (string s, string [] formats,
1916 DateTimeFormatInfo dfi, DateTimeStyles style, out DateTime ret,
1917 bool exact, ref bool longYear,
1918 bool setExceptionOnError, ref Exception exception)
1921 bool incompleteFormat = false;
1922 for (i = 0; i < formats.Length; i++)
1925 string format = formats[i];
1926 if (format == null || format == String.Empty)
1929 if (_DoParse (s, formats[i], null, exact, out result, dfi, style, false, ref incompleteFormat, ref longYear)) {
1935 if (setExceptionOnError)
1936 exception = new FormatException ("Invalid format string");
1937 ret = DateTime.MinValue;
1941 public TimeSpan Subtract (DateTime value)
1943 return new TimeSpan (ticks.Ticks) - value.ticks;
1946 public DateTime Subtract(TimeSpan value)
1950 newticks = (new TimeSpan (ticks.Ticks)) - value;
1951 DateTime ret = new DateTime (true,newticks);
1958 public long ToFileTime()
1960 DateTime universalTime = ToUniversalTime();
1962 if (universalTime.Ticks < w32file_epoch) {
1963 throw new ArgumentOutOfRangeException("file time is not valid");
1966 return(universalTime.Ticks - w32file_epoch);
1970 public long ToFileTimeUtc()
1972 if (Ticks < w32file_epoch) {
1973 throw new ArgumentOutOfRangeException("file time is not valid");
1976 return (Ticks - w32file_epoch);
1980 public string ToLongDateString()
1982 return ToString ("D");
1985 public string ToLongTimeString()
1987 return ToString ("T");
1990 public double ToOADate ()
1992 long t = this.Ticks;
1993 // uninitialized DateTime case
1996 // we can't reach minimum value
1997 if (t < 31242239136000000)
1998 return OAMinValue + 0.001;
2000 TimeSpan ts = new TimeSpan (this.Ticks - ticks18991230);
2001 double result = ts.TotalDays;
2002 // t < 0 (where 599264352000000000 == 0.0d for OA)
2003 if (t < 599264352000000000) {
2004 // negative days (int) but decimals are positive
2005 double d = Math.Ceiling (result);
2006 result = d - 2 - (result - d);
2009 // we can't reach maximum value
2010 if (result >= OAMaxValue)
2011 result = OAMaxValue - 0.00000001d;
2016 public string ToShortDateString()
2018 return ToString ("d");
2021 public string ToShortTimeString()
2023 return ToString ("t");
2026 public override string ToString ()
2028 return ToString ("G", null);
2031 public string ToString (IFormatProvider provider)
2033 return ToString (null, provider);
2036 public string ToString (string format)
2038 return ToString (format, null);
2041 public string ToString (string format, IFormatProvider provider)
2043 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
2045 if (format == null || format == String.Empty)
2048 bool useutc = false, use_invariant = false;
2050 if (format.Length == 1) {
2051 char fchar = format [0];
2052 format = DateTimeUtils.GetStandardPattern (fchar, dfi, out useutc, out use_invariant);
2054 return DateTimeUtils.ToString (ToUniversalTime (), format, dfi);
2055 // return ToUniversalTime()._ToString (format, dfi);
2058 throw new FormatException ("format is not one of the format specifier characters defined for DateTimeFormatInfo");
2061 // Don't convert UTC value. It just adds 'Z' for
2062 // 'u' format, for the same ticks.
2063 return DateTimeUtils.ToString (this, format, dfi);
2066 public DateTime ToLocalTime ()
2068 return TimeZone.CurrentTimeZone.ToLocalTime (this);
2071 public DateTime ToUniversalTime()
2073 return TimeZone.CurrentTimeZone.ToUniversalTime (this);
2078 public static DateTime operator +(DateTime d, TimeSpan t)
2080 DateTime ret = new DateTime (true, d.ticks + t);
2087 public static bool operator ==(DateTime d1, DateTime d2)
2089 return (d1.ticks == d2.ticks);
2092 public static bool operator >(DateTime t1,DateTime t2)
2094 return (t1.ticks > t2.ticks);
2097 public static bool operator >=(DateTime t1,DateTime t2)
2099 return (t1.ticks >= t2.ticks);
2102 public static bool operator !=(DateTime d1, DateTime d2)
2104 return (d1.ticks != d2.ticks);
2107 public static bool operator <(DateTime t1, DateTime t2)
2109 return (t1.ticks < t2.ticks );
2112 public static bool operator <=(DateTime t1,DateTime t2)
2114 return (t1.ticks <= t2.ticks);
2117 public static TimeSpan operator -(DateTime d1,DateTime d2)
2119 return new TimeSpan((d1.ticks - d2.ticks).Ticks);
2122 public static DateTime operator -(DateTime d,TimeSpan t)
2124 DateTime ret = new DateTime (true, d.ticks - t);
2131 bool IConvertible.ToBoolean(IFormatProvider provider)
2133 throw new InvalidCastException();
2136 byte IConvertible.ToByte(IFormatProvider provider)
2138 throw new InvalidCastException();
2142 char IConvertible.ToChar(IFormatProvider provider)
2144 throw new InvalidCastException();
2147 System.DateTime IConvertible.ToDateTime(IFormatProvider provider)
2152 decimal IConvertible.ToDecimal(IFormatProvider provider)
2154 throw new InvalidCastException();
2157 double IConvertible.ToDouble(IFormatProvider provider)
2159 throw new InvalidCastException();
2162 Int16 IConvertible.ToInt16(IFormatProvider provider)
2164 throw new InvalidCastException();
2167 Int32 IConvertible.ToInt32(IFormatProvider provider)
2169 throw new InvalidCastException();
2172 Int64 IConvertible.ToInt64(IFormatProvider provider)
2174 throw new InvalidCastException();
2178 #pragma warning disable 3019
2179 [CLSCompliant (false)]
2181 SByte IConvertible.ToSByte(IFormatProvider provider)
2183 throw new InvalidCastException();
2186 #pragma warning restore 3019
2189 Single IConvertible.ToSingle(IFormatProvider provider)
2191 throw new InvalidCastException();
2194 object IConvertible.ToType (Type type, IFormatProvider provider)
2197 throw new ArgumentNullException ("type");
2199 if (type == typeof (DateTime))
2201 else if (type == typeof (String))
2202 return this.ToString (provider);
2203 else if (type == typeof (Object))
2206 throw new InvalidCastException();
2210 #pragma warning disable 3019
2211 [CLSCompliant (false)]
2213 UInt16 IConvertible.ToUInt16(IFormatProvider provider)
2215 throw new InvalidCastException();
2218 #pragma warning restore 3019
2222 #pragma warning disable 3019
2223 [CLSCompliant (false)]
2225 UInt32 IConvertible.ToUInt32(IFormatProvider provider)
2227 throw new InvalidCastException();
2230 #pragma warning restore 3019
2234 #pragma warning disable 3019
2235 [CLSCompliant (false)]
2237 UInt64 IConvertible.ToUInt64(IFormatProvider provider)
2239 throw new InvalidCastException();
2242 #pragma warning restore 3019