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>
51 if (MonoTouchAOTHelper.FalseFlag) {
52 var comparer = new System.Collections.Generic.GenericComparer <DateTime> ();
53 var eqcomparer = new System.Collections.Generic.GenericEqualityComparer <DateTime> ();
57 private TimeSpan ticks;
61 private const int dp400 = 146097;
62 private const int dp100 = 36524;
63 private const int dp4 = 1461;
65 // w32 file time starts counting from 1/1/1601 00:00 GMT
66 // which is the constant ticks from the .NET epoch
67 private const long w32file_epoch = 504911232000000000L;
69 //private const long MAX_VALUE_TICKS = 3155378975400000000L;
70 // -- Microsoft .NET has this value.
71 private const long MAX_VALUE_TICKS = 3155378975999999999L;
74 // The UnixEpoch, it begins on Jan 1, 1970 at 0:0:0, expressed
77 internal const long UnixEpoch = 621355968000000000L;
79 // for OLE Automation dates
80 private const long ticks18991230 = 599264352000000000L;
81 private const double OAMinValue = -657435.0d;
82 private const double OAMaxValue = 2958466.0d;
84 public static readonly DateTime MaxValue = new DateTime (false, new TimeSpan (MAX_VALUE_TICKS));
85 public static readonly DateTime MinValue = new DateTime (false, new TimeSpan (0));
87 // DateTime.Parse patterns
88 // Patterns are divided to date and time patterns. The algorithm will
89 // try combinations of these patterns. The algorithm also looks for
90 // day of the week, AM/PM GMT and Z independently of the patterns.
91 private static readonly string[] ParseTimeFormats = new string [] {
99 "H tt", // Specifies AM to disallow '8'.
100 "H'\u6642'm'\u5206's'\u79D2'",
103 // DateTime.Parse date patterns extend ParseExact patterns as follows:
104 // MMM - month short name or month full name
105 // MMMM - month number or short name or month full name
107 // Parse behaves differently according to the ShorDatePattern of the
108 // DateTimeFormatInfo. The following define the date patterns for
109 // different orders of day, month and year in ShorDatePattern.
110 // Note that the year cannot go between the day and the month.
111 private static readonly string[] ParseYearDayMonthFormats = new string [] {
114 "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 [] {
205 private static readonly int[] daysmonth = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
206 private static readonly int[] daysmonthleap = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
208 private static int AbsoluteDays (int year, int month, int day)
213 days = (IsLeapYear(year) ? daysmonthleap : daysmonth);
217 return ((day-1) + temp + (365* (year-1)) + ((year-1)/4) - ((year-1)/100) + ((year-1)/400));
220 private int FromTicks(Which what)
222 int num400, num100, num4, numyears;
225 int[] days = daysmonth;
226 int totaldays = this.ticks.Days;
228 num400 = (totaldays / dp400);
229 totaldays -= num400 * dp400;
231 num100 = (totaldays / dp100);
232 if (num100 == 4) // leap
234 totaldays -= (num100 * dp100);
236 num4 = totaldays / dp4;
237 totaldays -= (num4 * dp4);
239 numyears = totaldays / 365 ;
241 if (numyears == 4) //leap
243 if (what == Which.Year )
244 return num400*400 + num100*100 + num4*4 + numyears + 1;
246 totaldays -= (numyears * 365) ;
247 if (what == Which.DayYear )
248 return totaldays + 1;
250 if ((numyears==3) && ((num100 == 3) || !(num4 == 24)) ) //31 dec leapyear
251 days = daysmonthleap;
253 while (totaldays >= days[M])
254 totaldays -= days[M++];
256 if (what == Which.Month )
266 /// Constructs a DateTime for specified ticks
269 public DateTime (long ticks)
271 this.ticks = new TimeSpan (ticks);
272 if (ticks < MinValue.Ticks || ticks > MaxValue.Ticks) {
273 string msg = Locale.GetText ("Value {0} is outside the valid range [{1},{2}].",
274 ticks, MinValue.Ticks, MaxValue.Ticks);
275 throw new ArgumentOutOfRangeException ("ticks", msg);
277 kind = DateTimeKind.Unspecified;
280 public DateTime (int year, int month, int day)
281 : this (year, month, day,0,0,0,0) {}
283 public DateTime (int year, int month, int day, int hour, int minute, int second)
284 : this (year, month, day, hour, minute, second, 0) {}
286 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond)
288 if ( year < 1 || year > 9999 ||
289 month < 1 || month >12 ||
290 day < 1 || day > DaysInMonth(year, month) ||
291 hour < 0 || hour > 23 ||
292 minute < 0 || minute > 59 ||
293 second < 0 || second > 59 ||
294 millisecond < 0 || millisecond > 999)
295 throw new ArgumentOutOfRangeException ("Parameters describe an " +
296 "unrepresentable DateTime.");
298 ticks = new TimeSpan (AbsoluteDays(year,month,day), hour, minute, second, millisecond);
300 kind = DateTimeKind.Unspecified;
303 public DateTime (int year, int month, int day, Calendar calendar)
304 : this (year, month, day, 0, 0, 0, 0, calendar)
308 public DateTime (int year, int month, int day, int hour, int minute, int second, Calendar calendar)
309 : this (year, month, day, hour, minute, second, 0, calendar)
313 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar)
315 if (calendar == null)
316 throw new ArgumentNullException ("calendar");
317 ticks = calendar.ToDateTime (year, month, day, hour, minute, second, millisecond).ticks;
318 kind = DateTimeKind.Unspecified;
321 internal DateTime (bool check, TimeSpan value)
323 if (check && (value.Ticks < MinValue.Ticks || value.Ticks > MaxValue.Ticks))
324 throw new ArgumentOutOfRangeException ();
328 kind = DateTimeKind.Unspecified;
331 public DateTime (long ticks, DateTimeKind kind) : this (ticks)
333 CheckDateTimeKind (kind);
337 public DateTime (int year, int month, int day, int hour, int minute, int second, DateTimeKind kind)
338 : this (year, month, day, hour, minute, second)
340 CheckDateTimeKind (kind);
344 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind)
345 : this (year, month, day, hour, minute, second, millisecond)
347 CheckDateTimeKind (kind);
351 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, DateTimeKind kind)
352 : this (year, month, day, hour, minute, second, millisecond, calendar)
354 CheckDateTimeKind (kind);
364 DateTime ret = new DateTime (Year, Month, Day);
374 return FromTicks(Which.Month);
382 return FromTicks(Which.Day);
386 public DayOfWeek DayOfWeek
390 return ( (DayOfWeek) ((ticks.Days+1) % 7) );
398 return FromTicks(Which.DayYear);
402 public TimeSpan TimeOfDay
406 return new TimeSpan(ticks.Ticks % TimeSpan.TicksPerDay );
423 return ticks.Minutes;
431 return ticks.Seconds;
435 public int Millisecond
439 return ticks.Milliseconds;
443 [MethodImplAttribute(MethodImplOptions.InternalCall)]
444 internal static extern long GetTimeMonotonic ();
446 [MethodImplAttribute(MethodImplOptions.InternalCall)]
447 internal static extern long GetNow ();
450 // To reduce the time consumed by DateTime.Now, we keep
451 // the difference to map the system time into a local
452 // time into `to_local_time_span', we record the timestamp
453 // for this in `last_now'
455 static object to_local_time_span_object;
456 static long last_now;
458 public static DateTime Now
462 long now = GetNow ();
463 DateTime dt = new DateTime (now);
465 if ((now - last_now) > TimeSpan.TicksPerMinute){
466 to_local_time_span_object = TimeZone.CurrentTimeZone.GetLocalTimeDiff (dt);
471 // This is boxed, so we avoid locking.
472 DateTime ret = dt + (TimeSpan) to_local_time_span_object;
473 ret.kind = DateTimeKind.Local;
486 public static DateTime Today
490 DateTime today = new DateTime (now.Year, now.Month, now.Day);
491 today.kind = now.kind;
496 public static DateTime UtcNow
499 return new DateTime (GetNow (), DateTimeKind.Utc);
507 return FromTicks(Which.Year);
511 public DateTimeKind Kind {
519 public DateTime Add (TimeSpan value)
521 DateTime ret = AddTicks (value.Ticks);
526 public DateTime AddDays (double value)
528 return AddMilliseconds (Math.Round (value * 86400000));
531 public DateTime AddTicks (long value)
533 if ((value + ticks.Ticks) > MAX_VALUE_TICKS || (value + ticks.Ticks) < 0) {
534 throw new ArgumentOutOfRangeException();
536 DateTime ret = new DateTime (value + ticks.Ticks);
541 public DateTime AddHours (double value)
543 return AddMilliseconds (value * 3600000);
546 public DateTime AddMilliseconds (double value)
548 if ((value * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
549 (value * TimeSpan.TicksPerMillisecond) < long.MinValue) {
550 throw new ArgumentOutOfRangeException();
552 long msticks = (long) Math.Round (value * TimeSpan.TicksPerMillisecond);
554 return AddTicks (msticks);
557 // required to match MS implementation for OADate (OLE Automation)
558 private DateTime AddRoundedMilliseconds (double ms)
560 if ((ms * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
561 (ms * TimeSpan.TicksPerMillisecond) < long.MinValue) {
562 throw new ArgumentOutOfRangeException ();
564 long msticks = (long) (ms += ms > 0 ? 0.5 : -0.5) * TimeSpan.TicksPerMillisecond;
566 return AddTicks (msticks);
569 public DateTime AddMinutes (double value)
571 return AddMilliseconds (value * 60000);
574 public DateTime AddMonths (int months)
576 int day, month, year, maxday ;
580 month = this.Month + (months % 12);
581 year = this.Year + months/12 ;
593 maxday = DaysInMonth(year, month);
597 temp = new DateTime (year, month, day);
599 return temp.Add (this.TimeOfDay);
602 public DateTime AddSeconds (double value)
604 return AddMilliseconds (value * 1000);
607 public DateTime AddYears (int value)
609 return AddMonths (value * 12);
612 public static int Compare (DateTime t1, DateTime t2)
614 if (t1.ticks < t2.ticks)
616 else if (t1.ticks > t2.ticks)
622 public int CompareTo (object value)
627 if (!(value is System.DateTime))
628 throw new ArgumentException (Locale.GetText (
629 "Value is not a System.DateTime"));
631 return Compare (this, (DateTime) value);
634 public bool IsDaylightSavingTime ()
636 if (kind == DateTimeKind.Utc)
638 return TimeZone.CurrentTimeZone.IsDaylightSavingTime (this);
641 public int CompareTo (DateTime value)
643 return Compare (this, value);
646 public bool Equals (DateTime value)
648 return value.ticks == ticks;
651 public long ToBinary ()
654 case DateTimeKind.Utc:
655 return Ticks | 0x4000000000000000;
656 case DateTimeKind.Local:
657 return (long) ((ulong) ToUniversalTime ().Ticks | 0x8000000000000000);
663 public static DateTime FromBinary (long dateData)
665 switch ((ulong)dateData >> 62) {
667 return new DateTime (dateData ^ 0x4000000000000000, DateTimeKind.Utc);
669 return new DateTime (dateData, DateTimeKind.Unspecified);
671 return new DateTime (dateData & 0x3fffffffffffffff, DateTimeKind.Utc).ToLocalTime ();
675 public static DateTime SpecifyKind (DateTime value, DateTimeKind kind)
677 return new DateTime (value.Ticks, kind);
680 public static int DaysInMonth (int year, int month)
684 if (month < 1 || month >12)
685 throw new ArgumentOutOfRangeException ();
687 if (year < 1 || year > 9999)
688 throw new ArgumentOutOfRangeException ();
690 days = (IsLeapYear(year) ? daysmonthleap : daysmonth);
694 public override bool Equals (object value)
696 if (!(value is System.DateTime))
699 return ((DateTime) value).ticks == ticks;
702 public static bool Equals (DateTime t1, DateTime t2 )
704 return (t1.ticks == t2.ticks );
707 public static DateTime FromFileTime (long fileTime)
710 throw new ArgumentOutOfRangeException ("fileTime", "< 0");
712 return new DateTime (w32file_epoch + fileTime).ToLocalTime ();
715 public static DateTime FromFileTimeUtc (long fileTime)
718 throw new ArgumentOutOfRangeException ("fileTime", "< 0");
720 return new DateTime (w32file_epoch + fileTime);
723 public static DateTime FromOADate (double d)
725 // An OLE Automation date is implemented as a floating-point number
726 // whose value is the number of days from midnight, 30 December 1899.
728 // d must be negative 657435.0 through positive 2958466.0.
729 if ((d <= OAMinValue) || (d >= OAMaxValue))
730 throw new ArgumentException ("d", "[-657435,2958466]");
732 DateTime dt = new DateTime (ticks18991230);
734 Double days = Math.Ceiling (d);
735 // integer part is the number of days (negative)
736 dt = dt.AddRoundedMilliseconds (days * 86400000);
737 // but decimals are the number of hours (in days fractions) and positive
738 Double hours = (days - d);
739 dt = dt.AddRoundedMilliseconds (hours * 86400000);
742 dt = dt.AddRoundedMilliseconds (d * 86400000);
748 public string[] GetDateTimeFormats()
750 return GetDateTimeFormats (CultureInfo.CurrentCulture);
753 public string[] GetDateTimeFormats(char format)
755 if ("dDgGfFmMrRstTuUyY".IndexOf (format) < 0)
756 throw new FormatException ("Invalid format character.");
757 string[] result = new string[1];
758 result[0] = this.ToString(format.ToString());
762 public string[] GetDateTimeFormats(IFormatProvider provider)
764 DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
765 // return GetDateTimeFormats (info.GetAllDateTimePatterns ());
766 ArrayList al = new ArrayList ();
767 foreach (char c in "dDgGfFmMrRstTuUyY")
768 al.AddRange (GetDateTimeFormats (c, info));
769 return al.ToArray (typeof (string)) as string [];
772 public string[] GetDateTimeFormats(char format,IFormatProvider provider )
774 if ("dDgGfFmMrRstTuUyY".IndexOf (format) < 0)
775 throw new FormatException ("Invalid format character.");
777 // LAMESPEC: There is NO assurance that 'U' ALWAYS
778 // euqals to 'F', but since we have to iterate all
779 // the pattern strings, we cannot just use
780 // ToString("U", provider) here. I believe that the
781 // method's behavior cannot be formalized.
782 bool adjustutc = false;
791 DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
792 return GetDateTimeFormats (adjustutc, info.GetAllRawDateTimePatterns (format), info);
795 private string [] GetDateTimeFormats (bool adjustutc, string [] patterns, DateTimeFormatInfo dfi)
797 string [] results = new string [patterns.Length];
798 DateTime val = adjustutc ? ToUniversalTime () : this;
799 for (int i = 0; i < results.Length; i++)
800 results [i] = DateTimeUtils.ToString (val, patterns [i], dfi);
804 private void CheckDateTimeKind (DateTimeKind kind) {
805 if ((kind != DateTimeKind.Unspecified) && (kind != DateTimeKind.Utc) && (kind != DateTimeKind.Local))
806 throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
809 public override int GetHashCode ()
811 return (int) ticks.Ticks;
814 public TypeCode GetTypeCode ()
816 return TypeCode.DateTime;
819 public static bool IsLeapYear (int year)
821 if (year < 1 || year > 9999)
822 throw new ArgumentOutOfRangeException ();
823 return ( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ;
826 public static DateTime Parse (string s)
828 return Parse (s, null);
831 public static DateTime Parse (string s, IFormatProvider provider)
833 return Parse (s, provider, DateTimeStyles.AllowWhiteSpaces);
836 public static DateTime Parse (string s, IFormatProvider provider, DateTimeStyles styles)
839 throw new ArgumentNullException ("s");
843 Exception exception = null;
844 if (!CoreParse (s, provider, styles, out res, out dto, true, ref exception))
850 const string formatExceptionMessage = "String was not recognized as a valid DateTime.";
852 internal static bool CoreParse (string s, IFormatProvider provider, DateTimeStyles styles,
853 out DateTime result, out DateTimeOffset dto, bool setExceptionOnError, ref Exception exception)
855 dto = new DateTimeOffset (0, TimeSpan.Zero);
856 if (s == null || s.Length == 0) {
857 if (setExceptionOnError)
858 exception = new FormatException (formatExceptionMessage);
863 if (provider == null)
864 provider = CultureInfo.CurrentCulture;
865 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
867 // Try first all the combinations of ParseAllDateFormats & ParseTimeFormats
868 string[] allDateFormats = YearMonthDayFormats (dfi, setExceptionOnError, ref exception);
869 if (allDateFormats == null){
874 bool longYear = false;
875 for (int i = 0; i < allDateFormats.Length; i++) {
876 string firstPart = allDateFormats [i];
877 bool incompleteFormat = false;
878 if (_DoParse (s, firstPart, "", false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
881 if (!incompleteFormat)
884 for (int j = 0; j < ParseTimeFormats.Length; j++) {
885 if (_DoParse (s, firstPart, ParseTimeFormats [j], false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
893 int dayIndex = dfi.MonthDayPattern.IndexOf('d');
894 int monthIndex = dfi.MonthDayPattern.IndexOf('M');
895 if (dayIndex == -1 || monthIndex == -1){
897 if (setExceptionOnError)
898 exception = new FormatException (Locale.GetText("Order of month and date is not defined by {0}", dfi.MonthDayPattern));
901 bool is_day_before_month = dayIndex < monthIndex;
902 string[] monthDayFormats = is_day_before_month ? DayMonthShortFormats : MonthDayShortFormats;
903 for (int i = 0; i < monthDayFormats.Length; i++) {
904 bool incompleteFormat = false;
905 if (_DoParse (s, monthDayFormats[i], "", false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
909 for (int j = 0; j < ParseTimeFormats.Length; j++) {
910 string firstPart = ParseTimeFormats [j];
911 bool incompleteFormat = false;
912 if (_DoParse (s, firstPart, "", false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
914 if (!incompleteFormat)
917 for (int i = 0; i < monthDayFormats.Length; i++) {
918 if (_DoParse (s, firstPart, monthDayFormats [i], false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
921 for (int i = 0; i < allDateFormats.Length; i++) {
922 string dateFormat = allDateFormats [i];
923 if (dateFormat[dateFormat.Length - 1] == 'T')
924 continue; // T formats must be before the time part
925 if (_DoParse (s, firstPart, dateFormat, false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
930 // Try as a last resort all the patterns
931 if (ParseExact (s, dfi.GetAllDateTimePatternsInternal (), dfi, styles, out result, false, ref longYear, setExceptionOnError, ref exception))
934 if (!setExceptionOnError)
937 // .NET 2.x does not throw an ArgumentOutOfRangeException, but .NET 1.1 does.
938 exception = new FormatException (formatExceptionMessage);
942 public static DateTime ParseExact (string s, string format, IFormatProvider provider)
944 return ParseExact (s, format, provider, DateTimeStyles.None);
947 private static string[] YearMonthDayFormats (DateTimeFormatInfo dfi, bool setExceptionOnError, ref Exception exc)
949 int dayIndex = dfi.ShortDatePattern.IndexOf('d');
950 int monthIndex = dfi.ShortDatePattern.IndexOf('M');
951 int yearIndex = dfi.ShortDatePattern.IndexOf('y');
952 if (dayIndex == -1 || monthIndex == -1 || yearIndex == -1){
953 if (setExceptionOnError)
954 exc = new FormatException (Locale.GetText("Order of year, month and date is not defined by {0}", dfi.ShortDatePattern));
958 if (yearIndex < monthIndex)
959 if (monthIndex < dayIndex)
960 return ParseYearMonthDayFormats;
961 else if (yearIndex < dayIndex)
962 return ParseYearDayMonthFormats;
964 // The year cannot be between the date and the month
965 if (setExceptionOnError)
966 exc = new FormatException (Locale.GetText("Order of date, year and month defined by {0} is not supported", dfi.ShortDatePattern));
969 else if (dayIndex < monthIndex)
970 return ParseDayMonthYearFormats;
971 else if (dayIndex < yearIndex)
972 return ParseMonthDayYearFormats;
974 // The year cannot be between the month and the date
975 if (setExceptionOnError)
976 exc = new FormatException (Locale.GetText("Order of month, year and date defined by {0} is not supported", dfi.ShortDatePattern));
981 private static int _ParseNumber (string s, int valuePos,
995 for (i = valuePos; i < s.Length && i < digits + valuePos; i++) {
996 if (!Char.IsDigit (s[i]))
1002 digits = real_digits;
1004 if (digits < min_digits) {
1009 if (s.Length - valuePos < digits) {
1014 for (i = valuePos; i < digits + valuePos; i++) {
1016 if (!Char.IsDigit (c)) {
1021 number = number * 10 + (byte) (c - '0');
1024 num_parsed = digits;
1028 private static int _ParseEnum (string s, int sPos, string[] values, string[] invValues, bool exact, out int num_parsed)
1030 // FIXME: I know this is somehow lame code. Probably
1031 // it should iterate all the enum value and return
1032 // the longest match. However right now I don't see
1033 // anything but "1" and "10" - "12" that might match
1034 // two or more values. (They are only abbrev month
1035 // names, so do reverse order search). See bug #80094.
1036 for (int i = values.Length - 1; i >= 0; i--) {
1037 if (!exact && invValues [i].Length > values[i].Length) {
1038 if (invValues [i].Length > 0 && _ParseString (s, sPos, 0, invValues [i], out num_parsed))
1040 if (values [i].Length > 0 && _ParseString (s, sPos, 0, values [i], out num_parsed))
1044 if (values [i].Length > 0 && _ParseString (s, sPos, 0, values [i], out num_parsed))
1046 if (!exact && invValues [i].Length > 0 && _ParseString (s, sPos, 0, invValues [i], out num_parsed))
1055 private static bool _ParseString (string s, int sPos, int maxlength, string value, out int num_parsed)
1058 maxlength = value.Length;
1060 if (sPos + maxlength <= s.Length && String.Compare (s, sPos, value, 0, maxlength, true, CultureInfo.InvariantCulture) == 0) {
1061 num_parsed = maxlength;
1069 // Note that in case of Parse (exact == false) we check both for AM/PM
1070 // and the culture spcific AM/PM strings.
1071 private static bool _ParseAmPm(string s,
1074 DateTimeFormatInfo dfi,
1083 if (!IsLetter (s, valuePos)) {
1084 if (dfi.AMDesignator != "")
1091 DateTimeFormatInfo invInfo = DateTimeFormatInfo.InvariantInfo;
1092 if (!exact && _ParseString (s, valuePos, num, invInfo.PMDesignator, out num_parsed) ||
1093 dfi.PMDesignator != "" && _ParseString(s, valuePos, num, dfi.PMDesignator, out num_parsed))
1095 else if (!exact && _ParseString (s, valuePos, num, invInfo.AMDesignator, out num_parsed) ||
1096 _ParseString (s, valuePos, num, dfi.AMDesignator, out num_parsed)) {
1097 if (exact || num_parsed != 0)
1105 // Note that in case of Parse (exact == false) we check both for ':'
1106 // and the culture spcific TimeSperator
1107 private static bool _ParseTimeSeparator (string s, int sPos, DateTimeFormatInfo dfi, bool exact, out int num_parsed)
1109 return _ParseString (s, sPos, 0, dfi.TimeSeparator, out num_parsed) ||
1110 !exact && _ParseString (s, sPos, 0, ":", out num_parsed);
1113 // Accept any character for DateSeparator, except TimeSeparator,
1114 // a digit or a letter.
1115 // Not documented, but seems to be MS behaviour here. See bug 54047.
1116 private static bool _ParseDateSeparator (string s, int sPos, DateTimeFormatInfo dfi, bool exact, out int num_parsed)
1119 if (exact && s [sPos] != '/')
1122 if (_ParseTimeSeparator (s, sPos, dfi, exact, out num_parsed) ||
1123 Char.IsDigit (s [sPos]) || Char.IsLetter (s [sPos]))
1130 private static bool IsLetter (string s, int pos)
1132 return pos < s.Length && Char.IsLetter (s [pos]);
1135 // To implement better DateTime.Parse we use two format strings one
1136 // for Date and one for Time. This allows us to define two different
1137 // arrays of formats for Time and Dates and to combine them more or less
1138 // efficiently. When this mode is used flexibleTwoPartsParsing is true.
1139 private static bool _DoParse (string s,
1143 out DateTime result,
1144 out DateTimeOffset dto,
1145 DateTimeFormatInfo dfi,
1146 DateTimeStyles style,
1147 bool firstPartIsDate,
1148 ref bool incompleteFormat,
1151 bool useutc = false;
1152 bool use_invariant = false;
1153 bool sloppy_parsing = false;
1154 dto = new DateTimeOffset (0, TimeSpan.Zero);
1155 bool flexibleTwoPartsParsing = !exact && secondPart != null;
1156 incompleteFormat = false;
1158 string format = firstPart;
1159 bool afterTFormat = false;
1160 DateTimeFormatInfo invInfo = DateTimeFormatInfo.InvariantInfo;
1161 if (format.Length == 1)
1162 format = DateTimeUtils.GetStandardPattern (format [0], dfi, out useutc, out use_invariant);
1164 result = new DateTime (0);
1171 if ((style & DateTimeStyles.AllowLeadingWhite) != 0) {
1172 format = format.TrimStart (null);
1174 s = s.TrimStart (null); // it could be optimized, but will make little good.
1177 if ((style & DateTimeStyles.AllowTrailingWhite) != 0) {
1178 format = format.TrimEnd (null);
1179 s = s.TrimEnd (null); // it could be optimized, but will make little good.
1185 if ((style & DateTimeStyles.AllowInnerWhite) != 0)
1186 sloppy_parsing = true;
1188 string chars = format;
1189 int len = format.Length, pos = 0, num = 0;
1193 int day = -1, dayofweek = -1, month = -1, year = -1;
1194 int hour = -1, minute = -1, second = -1;
1195 double fractionalSeconds = -1;
1197 int tzsign = -1, tzoffset = -1, tzoffmin = -1;
1198 bool isFirstPart = true;
1202 if (valuePos == s.Length)
1206 if (flexibleTwoPartsParsing && pos + num == 0)
1208 bool isLetter = IsLetter(s, valuePos);
1210 if (s [valuePos] == 'Z')
1213 _ParseString (s, valuePos, 0, "GMT", out num_parsed);
1214 if (num_parsed > 0 && !IsLetter (s, valuePos + num_parsed)) {
1215 valuePos += num_parsed;
1220 if (!afterTFormat && _ParseAmPm (s, valuePos, 0, dfi, exact, out num_parsed, ref ampm)) {
1221 if (IsLetter (s, valuePos + num_parsed))
1223 else if (num_parsed > 0) {
1224 valuePos += num_parsed;
1229 if (!afterTFormat && dayofweek == -1 && isLetter) {
1230 dayofweek = _ParseEnum (s, valuePos, dfi.RawDayNames, invInfo.RawDayNames, exact, out num_parsed);
1231 if (dayofweek == -1)
1232 dayofweek = _ParseEnum (s, valuePos, dfi.RawAbbreviatedDayNames, invInfo.RawAbbreviatedDayNames, exact, out num_parsed);
1233 if (dayofweek != -1 && !IsLetter (s, valuePos + num_parsed)) {
1234 valuePos += num_parsed;
1241 if (char.IsWhiteSpace (s [valuePos]) || s [valuePos] == ',') {
1248 if (pos + num >= len)
1250 if (flexibleTwoPartsParsing && num == 0) {
1251 afterTFormat = isFirstPart && firstPart [firstPart.Length - 1] == 'T';
1252 if (!isFirstPart && format == "")
1257 format = secondPart;
1262 isFirstPart = false;
1268 bool leading_zeros = true;
1270 if (chars[pos] == '\'') {
1272 while (pos+num < len) {
1273 if (chars[pos+num] == '\'')
1276 if (valuePos == s.Length || s [valuePos] != chars [pos + num])
1286 } else if (chars[pos] == '"') {
1288 while (pos+num < len) {
1289 if (chars[pos+num] == '"')
1292 if (valuePos == s.Length || s [valuePos] != chars[pos+num])
1302 } else if (chars[pos] == '\\') {
1307 if (s [valuePos] != chars [pos])
1313 } else if (chars[pos] == '%') {
1316 } else if (char.IsWhiteSpace (s [valuePos]) ||
1317 s [valuePos] == ',' && (!exact && chars [pos] == '/' || Char.IsWhiteSpace (chars [pos]))) {
1320 if (exact && (style & DateTimeStyles.AllowInnerWhite) == 0) {
1321 if (!Char.IsWhiteSpace (chars[pos]))
1328 while (ws < s.Length) {
1329 if (Char.IsWhiteSpace (s [ws]) || s [ws] == ',')
1336 while (ws < chars.Length) {
1337 if (Char.IsWhiteSpace (chars [ws]) || chars [ws] == ',')
1343 // A whitespace may match a '/' in the pattern.
1344 if (!exact && pos < chars.Length && chars[pos] == '/')
1345 if (!_ParseDateSeparator (s, valuePos, dfi, exact, out num_parsed))
1350 if ((pos+num+1 < len) && (chars[pos+num+1] == chars[pos+num])) {
1358 if (num < 2 && day != -1 || num >= 2 && dayofweek != -1)
1361 day = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1363 day = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1365 dayofweek = _ParseEnum (s, valuePos, dfi.RawAbbreviatedDayNames, invInfo.RawAbbreviatedDayNames, exact, out num_parsed);
1367 dayofweek = _ParseEnum (s, valuePos, dfi.RawDayNames, invInfo.RawDayNames, exact, out num_parsed);
1373 if (flexibleTwoPartsParsing) {
1375 if (num == 0 || num == 3)
1376 month = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1377 if (num > 1 && num_parsed == -1)
1378 month = _ParseEnum (s, valuePos, dfi.RawMonthNames, invInfo.RawMonthNames, exact, out num_parsed) + 1;
1379 if (num > 1 && num_parsed == -1)
1380 month = _ParseEnum (s, valuePos, dfi.RawAbbreviatedMonthNames, invInfo.RawAbbreviatedMonthNames, exact, out num_parsed) + 1;
1385 month = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1387 month = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1389 month = _ParseEnum (s, valuePos, dfi.RawAbbreviatedMonthNames, invInfo.RawAbbreviatedMonthNames, exact, out num_parsed) + 1;
1391 month = _ParseEnum (s, valuePos, dfi.RawMonthNames, invInfo.RawMonthNames, exact, out num_parsed) + 1;
1398 year = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1399 } else if (num < 3) {
1400 year = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1402 year = _ParseNumber (s, valuePos, exact ? 4 : 3, 4, false, sloppy_parsing, out num_parsed);
1403 if ((year >= 1000) && (num_parsed == 4) && (!longYear) && (s.Length > 4 + valuePos)) {
1405 int ly = _ParseNumber (s, valuePos, 5, 5, false, sloppy_parsing, out np);
1406 longYear = (ly > 9999);
1411 //FIXME: We should do use dfi.Calendat.TwoDigitYearMax
1412 if (num_parsed <= 2)
1413 year += (year < 30) ? 2000 : 1900;
1419 hour = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1421 hour = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1430 if (hour != -1 || !flexibleTwoPartsParsing && ampm >= 0)
1433 hour = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1435 hour = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1446 minute = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1448 minute = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1458 second = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1460 second = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1467 leading_zeros = false;
1470 if (num > 6 || fractionalSeconds != -1)
1472 double decimalNumber = (double) _ParseNumber (s, valuePos, 0, num+1, leading_zeros, sloppy_parsing, out num_parsed);
1473 if (num_parsed == -1)
1475 fractionalSeconds = decimalNumber / Math.Pow(10.0, num_parsed);
1478 if (!_ParseAmPm (s, valuePos, num > 0 ? 0 : 1, dfi, exact, out num_parsed, ref ampm))
1485 if (s [valuePos] == '+')
1487 else if (s [valuePos] == '-')
1494 tzoffset = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1496 tzoffset = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1498 tzoffset = _ParseNumber (s, valuePos, 1, 2, true, /*sloppy_parsing*/true, out num_parsed);
1499 valuePos += num_parsed;
1504 if (valuePos < s.Length && Char.IsDigit (s [valuePos]) ||
1505 _ParseTimeSeparator (s, valuePos, dfi, exact, out num_parsed)) {
1506 valuePos += num_parsed;
1507 tzoffmin = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1511 else if (!flexibleTwoPartsParsing)
1518 if (s [valuePos] == 'Z') {
1522 else if (s [valuePos] == '+' || s [valuePos] == '-') {
1525 if (s [valuePos] == '+')
1527 else if (s [valuePos] == '-')
1532 tzoffset = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1533 valuePos += num_parsed;
1537 if (Char.IsDigit (s [valuePos]))
1539 else if (!_ParseString (s, valuePos, 0, dfi.TimeSeparator, out num_parsed))
1541 valuePos += num_parsed;
1543 tzoffmin = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1550 // LAMESPEC: This should be part of UTCpattern
1551 // string and thus should not be considered here.
1553 // Note that 'Z' is not defined as a pattern
1554 // character. Keep it for X509 certificate
1555 // verification. Also, "Z" != "'Z'" under MS.NET
1556 // ("'Z'" is just literal; handled above)
1558 if (s [valuePos] != 'Z')
1565 if (s [valuePos] != 'G')
1568 if ((pos + 2 < len) && (valuePos + 2 < s.Length) &&
1569 (chars [pos + 1] == 'M') && (s[valuePos + 1] == 'M') &&
1570 (chars [pos + 2] == 'T') && (s[valuePos + 2] == 'T'))
1582 if (!_ParseTimeSeparator (s, valuePos, dfi, exact, out num_parsed))
1586 if (!_ParseDateSeparator (s, valuePos, dfi, exact, out num_parsed))
1592 if (s [valuePos] != chars [pos])
1603 valuePos += num_parsed;
1605 if (!exact && !flexibleTwoPartsParsing) {
1606 switch (chars [pos]) {
1612 if (s.Length > valuePos && s [valuePos] == 'Z' &&
1613 (pos + 1 == chars.Length || chars [pos + 1] != 'Z')) {
1621 pos = pos + num + 1;
1625 if (pos + 1 < len && chars [pos] == '.' && chars [pos + 1] == 'F') {
1627 while (pos < len && chars [pos] == 'F') // '.FFF....' can be mapped to nothing. See bug #444103
1630 while (pos < len && chars [pos] == 'K') // 'K' can be mapped to nothing
1636 if (s.Length > valuePos) // extraneous tail.
1641 if (Char.IsDigit (s [valuePos]) && Char.IsDigit (s [valuePos - 1]))
1643 if (Char.IsLetter (s [valuePos]) && Char.IsLetter (s [valuePos - 1]))
1645 incompleteFormat = true;
1656 if (fractionalSeconds == -1)
1657 fractionalSeconds = 0;
1659 // If no date was given
1660 if ((day == -1) && (month == -1) && (year == -1)) {
1661 if ((style & DateTimeStyles.NoCurrentDateDefault) != 0) {
1666 day = DateTime.Today.Day;
1667 month = DateTime.Today.Month;
1668 year = DateTime.Today.Year;
1677 if ((style & DateTimeStyles.NoCurrentDateDefault) != 0)
1680 year = DateTime.Today.Year;
1683 if (ampm == 0 && hour == 12)
1686 if (ampm == 1 && (!flexibleTwoPartsParsing || hour < 12))
1689 // For anything out of range
1691 if (year < 1 || year > 9999 ||
1692 month < 1 || month >12 ||
1693 day < 1 || day > DateTime.DaysInMonth(year, month) ||
1694 hour < 0 || hour > 23 ||
1695 minute < 0 || minute > 59 ||
1696 second < 0 || second > 59)
1699 result = new DateTime (year, month, day, hour, minute, second, 0);
1700 result = result.AddSeconds(fractionalSeconds);
1702 if (dayofweek != -1 && dayofweek != (int) result.DayOfWeek)
1706 if (result != DateTime.MinValue) {
1708 dto = new DateTimeOffset (result);
1709 } catch { } // We handle this error in DateTimeOffset.Parse
1717 tzoffset = -tzoffset;
1718 tzoffmin = -tzoffmin;
1721 dto = new DateTimeOffset (result, new TimeSpan (tzoffset, tzoffmin, 0));
1722 } catch {} // We handle this error in DateTimeOffset.Parse
1724 bool adjustToUniversal = (style & DateTimeStyles.AdjustToUniversal) != 0;
1727 long newticks = (result.ticks - dto.Offset).Ticks;
1729 newticks += TimeSpan.TicksPerDay;
1730 result = new DateTime (false, new TimeSpan (newticks));
1731 result.kind = DateTimeKind.Utc;
1732 if ((style & DateTimeStyles.RoundtripKind) != 0)
1733 result = result.ToLocalTime ();
1735 else if (useutc || ((style & DateTimeStyles.AssumeUniversal) != 0))
1736 result.kind = DateTimeKind.Utc;
1737 else if ((style & DateTimeStyles.AssumeLocal) != 0)
1738 result.kind = DateTimeKind.Local;
1740 bool adjustToLocal = !adjustToUniversal && (style & DateTimeStyles.RoundtripKind) == 0;
1741 if (result.kind != DateTimeKind.Unspecified)
1743 if (adjustToUniversal)
1744 result = result.ToUniversalTime ();
1745 else if (adjustToLocal)
1746 result = result.ToLocalTime ();
1751 public static DateTime ParseExact (string s, string format,
1752 IFormatProvider provider, DateTimeStyles style)
1755 throw new ArgumentNullException ("format");
1757 string [] formats = new string [1];
1758 formats[0] = format;
1760 return ParseExact (s, formats, provider, style);
1763 public static DateTime ParseExact (string s, string[] formats,
1764 IFormatProvider provider,
1765 DateTimeStyles style)
1767 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
1770 throw new ArgumentNullException ("s");
1771 if (formats == null)
1772 throw new ArgumentNullException ("formats");
1773 if (formats.Length == 0)
1774 throw new FormatException ("Format specifier was invalid.");
1777 bool longYear = false;
1779 if (!ParseExact (s, formats, dfi, style, out result, true, ref longYear, true, ref e))
1784 private static void CheckStyle (DateTimeStyles style)
1786 if ( (style & DateTimeStyles.RoundtripKind) != 0)
1788 if ((style & DateTimeStyles.AdjustToUniversal) != 0 || (style & DateTimeStyles.AssumeLocal) != 0 ||
1789 (style & DateTimeStyles.AssumeUniversal) != 0)
1790 throw new ArgumentException ("The DateTimeStyles value RoundtripKind cannot be used with the values AssumeLocal, Asersal or AdjustToUniversal.", "style");
1792 if ((style & DateTimeStyles.AssumeUniversal) != 0 && (style & DateTimeStyles.AssumeLocal) != 0)
1793 throw new ArgumentException ("The DateTimeStyles values AssumeLocal and AssumeUniversal cannot be used together.", "style");
1796 public static bool TryParse (string s, out DateTime result)
1800 Exception exception = null;
1803 return CoreParse (s, null, DateTimeStyles.AllowWhiteSpaces, out result, out dto, false, ref exception);
1810 public static bool TryParse (string s, IFormatProvider provider, DateTimeStyles styles, out DateTime result)
1814 Exception exception = null;
1817 return CoreParse (s, provider, styles, out result, out dto, false, ref exception);
1824 public static bool TryParseExact (string s, string format,
1825 IFormatProvider provider,
1826 DateTimeStyles style,
1827 out DateTime result)
1830 formats = new string [1];
1831 formats[0] = format;
1833 return TryParseExact (s, formats, provider, style, out result);
1836 public static bool TryParseExact (string s, string[] formats,
1837 IFormatProvider provider,
1838 DateTimeStyles style,
1839 out DateTime result)
1842 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
1844 bool longYear = false;
1846 return ParseExact (s, formats, dfi, style, out result, true, ref longYear, false, ref e);
1853 private static bool ParseExact (string s, string [] formats,
1854 DateTimeFormatInfo dfi, DateTimeStyles style, out DateTime ret,
1855 bool exact, ref bool longYear,
1856 bool setExceptionOnError, ref Exception exception)
1859 bool incompleteFormat = false;
1860 for (i = 0; i < formats.Length; i++)
1863 string format = formats[i];
1864 if (format == null || format == String.Empty)
1868 if (_DoParse (s, formats[i], null, exact, out result, out dto, dfi, style, false, ref incompleteFormat, ref longYear)) {
1874 if (setExceptionOnError)
1875 exception = new FormatException ("Invalid format string");
1876 ret = DateTime.MinValue;
1880 public TimeSpan Subtract (DateTime value)
1882 return new TimeSpan (ticks.Ticks) - value.ticks;
1885 public DateTime Subtract(TimeSpan value)
1889 newticks = (new TimeSpan (ticks.Ticks)) - value;
1890 DateTime ret = new DateTime (true,newticks);
1895 public long ToFileTime()
1897 DateTime universalTime = ToUniversalTime();
1899 if (universalTime.Ticks < w32file_epoch) {
1900 throw new ArgumentOutOfRangeException("file time is not valid");
1903 return(universalTime.Ticks - w32file_epoch);
1906 public long ToFileTimeUtc()
1908 if (Ticks < w32file_epoch) {
1909 throw new ArgumentOutOfRangeException("file time is not valid");
1912 return (Ticks - w32file_epoch);
1915 public string ToLongDateString()
1917 return ToString ("D");
1920 public string ToLongTimeString()
1922 return ToString ("T");
1925 public double ToOADate ()
1927 long t = this.Ticks;
1928 // uninitialized DateTime case
1931 // we can't reach minimum value
1932 if (t < 31242239136000000)
1933 return OAMinValue + 0.001;
1935 TimeSpan ts = new TimeSpan (this.Ticks - ticks18991230);
1936 double result = ts.TotalDays;
1937 // t < 0 (where 599264352000000000 == 0.0d for OA)
1938 if (t < 599264352000000000) {
1939 // negative days (int) but decimals are positive
1940 double d = Math.Ceiling (result);
1941 result = d - 2 - (result - d);
1944 // we can't reach maximum value
1945 if (result >= OAMaxValue)
1946 result = OAMaxValue - 0.00000001d;
1951 public string ToShortDateString()
1953 return ToString ("d");
1956 public string ToShortTimeString()
1958 return ToString ("t");
1961 public override string ToString ()
1963 return ToString ("G", null);
1966 public string ToString (IFormatProvider provider)
1968 return ToString (null, provider);
1971 public string ToString (string format)
1973 return ToString (format, null);
1976 public string ToString (string format, IFormatProvider provider)
1978 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
1980 if (format == null || format == String.Empty)
1983 bool useutc = false, use_invariant = false;
1985 if (format.Length == 1) {
1986 char fchar = format [0];
1987 format = DateTimeUtils.GetStandardPattern (fchar, dfi, out useutc, out use_invariant);
1989 return DateTimeUtils.ToString (ToUniversalTime (), format, dfi);
1990 // return ToUniversalTime()._ToString (format, dfi);
1993 throw new FormatException ("format is not one of the format specifier characters defined for DateTimeFormatInfo");
1996 // Don't convert UTC value. It just adds 'Z' for
1997 // 'u' format, for the same ticks.
1998 return DateTimeUtils.ToString (this, format, dfi);
2001 public DateTime ToLocalTime ()
2003 return TimeZone.CurrentTimeZone.ToLocalTime (this);
2006 public DateTime ToUniversalTime()
2008 return TimeZone.CurrentTimeZone.ToUniversalTime (this);
2013 public static DateTime operator +(DateTime d, TimeSpan t)
2015 DateTime ret = new DateTime (true, d.ticks + t);
2020 public static bool operator ==(DateTime d1, DateTime d2)
2022 return (d1.ticks == d2.ticks);
2025 public static bool operator >(DateTime t1,DateTime t2)
2027 return (t1.ticks > t2.ticks);
2030 public static bool operator >=(DateTime t1,DateTime t2)
2032 return (t1.ticks >= t2.ticks);
2035 public static bool operator !=(DateTime d1, DateTime d2)
2037 return (d1.ticks != d2.ticks);
2040 public static bool operator <(DateTime t1, DateTime t2)
2042 return (t1.ticks < t2.ticks );
2045 public static bool operator <=(DateTime t1,DateTime t2)
2047 return (t1.ticks <= t2.ticks);
2050 public static TimeSpan operator -(DateTime d1,DateTime d2)
2052 return new TimeSpan((d1.ticks - d2.ticks).Ticks);
2055 public static DateTime operator -(DateTime d,TimeSpan t)
2057 DateTime ret = new DateTime (true, d.ticks - t);
2062 bool IConvertible.ToBoolean(IFormatProvider provider)
2064 throw new InvalidCastException();
2067 byte IConvertible.ToByte(IFormatProvider provider)
2069 throw new InvalidCastException();
2073 char IConvertible.ToChar(IFormatProvider provider)
2075 throw new InvalidCastException();
2078 System.DateTime IConvertible.ToDateTime(IFormatProvider provider)
2083 decimal IConvertible.ToDecimal(IFormatProvider provider)
2085 throw new InvalidCastException();
2088 double IConvertible.ToDouble(IFormatProvider provider)
2090 throw new InvalidCastException();
2093 Int16 IConvertible.ToInt16(IFormatProvider provider)
2095 throw new InvalidCastException();
2098 Int32 IConvertible.ToInt32(IFormatProvider provider)
2100 throw new InvalidCastException();
2103 Int64 IConvertible.ToInt64(IFormatProvider provider)
2105 throw new InvalidCastException();
2108 SByte IConvertible.ToSByte(IFormatProvider provider)
2110 throw new InvalidCastException();
2113 Single IConvertible.ToSingle(IFormatProvider provider)
2115 throw new InvalidCastException();
2118 object IConvertible.ToType (Type targetType, IFormatProvider provider)
2120 if (targetType == null)
2121 throw new ArgumentNullException ("targetType");
2123 if (targetType == typeof (DateTime))
2125 else if (targetType == typeof (String))
2126 return this.ToString (provider);
2127 else if (targetType == typeof (Object))
2130 throw new InvalidCastException();
2133 UInt16 IConvertible.ToUInt16(IFormatProvider provider)
2135 throw new InvalidCastException();
2138 UInt32 IConvertible.ToUInt32(IFormatProvider provider)
2140 throw new InvalidCastException();
2143 UInt64 IConvertible.ToUInt64(IFormatProvider provider)
2145 throw new InvalidCastException();