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 internal struct DateTimeOffset {
59 public DateTime DateTime;
60 public TimeSpan Offset;
62 public DateTimeOffset (DateTime dt) : this (dt, TimeSpan.Zero)
66 public DateTimeOffset (long ticks, TimeSpan offset) : this (new DateTime (ticks), offset)
70 public DateTimeOffset (DateTime dt, TimeSpan offset)
78 private const int dp400 = 146097;
79 private const int dp100 = 36524;
80 private const int dp4 = 1461;
82 // w32 file time starts counting from 1/1/1601 00:00 GMT
83 // which is the constant ticks from the .NET epoch
84 private const long w32file_epoch = 504911232000000000L;
86 //private const long MAX_VALUE_TICKS = 3155378975400000000L;
87 // -- Microsoft .NET has this value.
88 private const long MAX_VALUE_TICKS = 3155378975999999999L;
91 // The UnixEpoch, it begins on Jan 1, 1970 at 0:0:0, expressed
94 internal const long UnixEpoch = 621355968000000000L;
96 // for OLE Automation dates
97 private const long ticks18991230 = 599264352000000000L;
98 private const double OAMinValue = -657435.0d;
99 private const double OAMaxValue = 2958466.0d;
101 public static readonly DateTime MaxValue = new DateTime (false, new TimeSpan (MAX_VALUE_TICKS));
102 public static readonly DateTime MinValue = new DateTime (false, new TimeSpan (0));
104 // DateTime.Parse patterns
105 // Patterns are divided to date and time patterns. The algorithm will
106 // try combinations of these patterns. The algorithm also looks for
107 // day of the week, AM/PM GMT and Z independently of the patterns.
108 private static readonly string[] ParseTimeFormats = new string [] {
116 "H tt", // Specifies AM to disallow '8'.
117 "H'\u6642'm'\u5206's'\u79D2'",
120 // DateTime.Parse date patterns extend ParseExact patterns as follows:
121 // MMM - month short name or month full name
122 // MMMM - month number or short name or month full name
124 // Parse behaves differently according to the ShorDatePattern of the
125 // DateTimeFormatInfo. The following define the date patterns for
126 // different orders of day, month and year in ShorDatePattern.
127 // Note that the year cannot go between the day and the month.
128 private static readonly string[] ParseYearDayMonthFormats = new string [] {
131 "yyyy'\u5E74'M'\u6708'd'\u65E5",
148 private static readonly string[] ParseYearMonthDayFormats = new string [] {
151 "yyyy'\u5E74'M'\u6708'd'\u65E5",
165 private static readonly string[] ParseDayMonthYearFormats = new string [] {
168 "yyyy'\u5E74'M'\u6708'd'\u65E5",
185 private static readonly string[] ParseMonthDayYearFormats = new string [] {
188 "yyyy'\u5E74'M'\u6708'd'\u65E5",
205 // Patterns influenced by the MonthDayPattern in DateTimeFormatInfo.
206 // Note that these patterns cannot be followed by the time.
207 private static readonly string[] MonthDayShortFormats = new string [] {
212 private static readonly string[] DayMonthShortFormats = new string [] {
216 #else // In .Net 1.0 Feb 03 is always Feb 3rd (and not Feb 2003)
230 private static readonly int[] daysmonth = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
231 private static readonly int[] daysmonthleap = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
233 private static int AbsoluteDays (int year, int month, int day)
238 days = (IsLeapYear(year) ? daysmonthleap : daysmonth);
242 return ((day-1) + temp + (365* (year-1)) + ((year-1)/4) - ((year-1)/100) + ((year-1)/400));
245 private int FromTicks(Which what)
247 int num400, num100, num4, numyears;
250 int[] days = daysmonth;
251 int totaldays = this.ticks.Days;
253 num400 = (totaldays / dp400);
254 totaldays -= num400 * dp400;
256 num100 = (totaldays / dp100);
257 if (num100 == 4) // leap
259 totaldays -= (num100 * dp100);
261 num4 = totaldays / dp4;
262 totaldays -= (num4 * dp4);
264 numyears = totaldays / 365 ;
266 if (numyears == 4) //leap
268 if (what == Which.Year )
269 return num400*400 + num100*100 + num4*4 + numyears + 1;
271 totaldays -= (numyears * 365) ;
272 if (what == Which.DayYear )
273 return totaldays + 1;
275 if ((numyears==3) && ((num100 == 3) || !(num4 == 24)) ) //31 dec leapyear
276 days = daysmonthleap;
278 while (totaldays >= days[M])
279 totaldays -= days[M++];
281 if (what == Which.Month )
291 /// Constructs a DateTime for specified ticks
294 public DateTime (long ticks)
296 this.ticks = new TimeSpan (ticks);
297 if (ticks < MinValue.Ticks || ticks > MaxValue.Ticks) {
298 string msg = Locale.GetText ("Value {0} is outside the valid range [{1},{2}].",
299 ticks, MinValue.Ticks, MaxValue.Ticks);
300 throw new ArgumentOutOfRangeException ("ticks", msg);
303 kind = DateTimeKind.Unspecified;
307 public DateTime (int year, int month, int day)
308 : this (year, month, day,0,0,0,0) {}
310 public DateTime (int year, int month, int day, int hour, int minute, int second)
311 : this (year, month, day, hour, minute, second, 0) {}
313 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond)
315 if ( year < 1 || year > 9999 ||
316 month < 1 || month >12 ||
317 day < 1 || day > DaysInMonth(year, month) ||
318 hour < 0 || hour > 23 ||
319 minute < 0 || minute > 59 ||
320 second < 0 || second > 59 ||
321 millisecond < 0 || millisecond > 999)
322 throw new ArgumentOutOfRangeException ("Parameters describe an " +
323 "unrepresentable DateTime.");
325 ticks = new TimeSpan (AbsoluteDays(year,month,day), hour, minute, second, millisecond);
328 kind = DateTimeKind.Unspecified;
332 public DateTime (int year, int month, int day, Calendar calendar)
333 : this (year, month, day, 0, 0, 0, 0, calendar)
337 public DateTime (int year, int month, int day, int hour, int minute, int second, Calendar calendar)
338 : this (year, month, day, hour, minute, second, 0, calendar)
342 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar)
344 if (calendar == null)
345 throw new ArgumentNullException ("calendar");
346 ticks = calendar.ToDateTime (year, month, day, hour, minute, second, millisecond).ticks;
348 kind = DateTimeKind.Unspecified;
352 internal DateTime (bool check, TimeSpan value)
354 if (check && (value.Ticks < MinValue.Ticks || value.Ticks > MaxValue.Ticks))
355 throw new ArgumentOutOfRangeException ();
360 kind = DateTimeKind.Unspecified;
365 public DateTime (long ticks, DateTimeKind kind) : this (ticks)
367 CheckDateTimeKind (kind);
371 public DateTime (int year, int month, int day, int hour, int minute, int second, DateTimeKind kind)
372 : this (year, month, day, hour, minute, second)
374 CheckDateTimeKind (kind);
378 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind)
379 : this (year, month, day, hour, minute, second, millisecond)
381 CheckDateTimeKind (kind);
385 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, DateTimeKind kind)
386 : this (year, month, day, hour, minute, second, millisecond, calendar)
388 CheckDateTimeKind (kind);
399 DateTime ret = new DateTime (Year, Month, Day);
411 return FromTicks(Which.Month);
419 return FromTicks(Which.Day);
423 public DayOfWeek DayOfWeek
427 return ( (DayOfWeek) ((ticks.Days+1) % 7) );
435 return FromTicks(Which.DayYear);
439 public TimeSpan TimeOfDay
443 return new TimeSpan(ticks.Ticks % TimeSpan.TicksPerDay );
460 return ticks.Minutes;
468 return ticks.Seconds;
472 public int Millisecond
476 return ticks.Milliseconds;
480 [MethodImplAttribute(MethodImplOptions.InternalCall)]
481 internal static extern long GetTimeMonotonic ();
483 [MethodImplAttribute(MethodImplOptions.InternalCall)]
484 internal static extern long GetNow ();
487 // To reduce the time consumed by DateTime.Now, we keep
488 // the difference to map the system time into a local
489 // time into `to_local_time_span', we record the timestamp
490 // for this in `last_now'
492 static object to_local_time_span_object;
493 static long last_now;
495 public static DateTime Now
499 long now = GetNow ();
500 DateTime dt = new DateTime (now);
502 if ((now - last_now) > TimeSpan.TicksPerMinute){
503 to_local_time_span_object = TimeZone.CurrentTimeZone.GetLocalTimeDiff (dt);
508 // This is boxed, so we avoid locking.
509 DateTime ret = dt + (TimeSpan) to_local_time_span_object;
511 ret.kind = DateTimeKind.Local;
525 public static DateTime Today
529 DateTime today = new DateTime (now.Year, now.Month, now.Day);
531 today.kind = now.kind;
537 public static DateTime UtcNow
541 return new DateTime (GetNow (), DateTimeKind.Utc);
543 return new DateTime (GetNow ());
552 return FromTicks(Which.Year);
557 public DateTimeKind Kind {
566 public DateTime Add (TimeSpan value)
568 DateTime ret = AddTicks (value.Ticks);
575 public DateTime AddDays (double value)
577 return AddMilliseconds (Math.Round (value * 86400000));
580 public DateTime AddTicks (long value)
582 if ((value + ticks.Ticks) > MAX_VALUE_TICKS || (value + ticks.Ticks) < 0) {
583 throw new ArgumentOutOfRangeException();
585 DateTime ret = new DateTime (value + ticks.Ticks);
592 public DateTime AddHours (double value)
594 return AddMilliseconds (value * 3600000);
597 public DateTime AddMilliseconds (double value)
599 if ((value * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
600 (value * TimeSpan.TicksPerMillisecond) < long.MinValue) {
601 throw new ArgumentOutOfRangeException();
603 long msticks = (long) (value * TimeSpan.TicksPerMillisecond);
605 return AddTicks (msticks);
608 // required to match MS implementation for OADate (OLE Automation)
609 private DateTime AddRoundedMilliseconds (double ms)
611 if ((ms * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
612 (ms * TimeSpan.TicksPerMillisecond) < long.MinValue) {
613 throw new ArgumentOutOfRangeException ();
615 long msticks = (long) (ms += ms > 0 ? 0.5 : -0.5) * TimeSpan.TicksPerMillisecond;
617 return AddTicks (msticks);
620 public DateTime AddMinutes (double value)
622 return AddMilliseconds (value * 60000);
625 public DateTime AddMonths (int months)
627 int day, month, year, maxday ;
631 month = this.Month + (months % 12);
632 year = this.Year + months/12 ;
644 maxday = DaysInMonth(year, month);
648 temp = new DateTime (year, month, day);
652 return temp.Add (this.TimeOfDay);
655 public DateTime AddSeconds (double value)
657 return AddMilliseconds (value * 1000);
660 public DateTime AddYears (int value)
662 return AddMonths (value * 12);
665 public static int Compare (DateTime t1, DateTime t2)
667 if (t1.ticks < t2.ticks)
669 else if (t1.ticks > t2.ticks)
675 public int CompareTo (object value)
680 if (!(value is System.DateTime))
681 throw new ArgumentException (Locale.GetText (
682 "Value is not a System.DateTime"));
684 return Compare (this, (DateTime) value);
688 public bool IsDaylightSavingTime ()
690 if (kind == DateTimeKind.Utc)
692 return TimeZone.CurrentTimeZone.IsDaylightSavingTime (this);
695 public int CompareTo (DateTime value)
697 return Compare (this, value);
700 public bool Equals (DateTime value)
702 return value.ticks == ticks;
705 public long ToBinary ()
708 case DateTimeKind.Utc:
709 return Ticks | 0x4000000000000000;
710 case DateTimeKind.Local:
711 return (long) ((ulong) ToUniversalTime ().Ticks | 0x8000000000000000);
717 public static DateTime FromBinary (long dateData)
719 switch ((ulong)dateData >> 62) {
721 return new DateTime (dateData ^ 0x4000000000000000, DateTimeKind.Utc);
723 return new DateTime (dateData, DateTimeKind.Unspecified);
725 return new DateTime (dateData & 0x3fffffffffffffff, DateTimeKind.Utc).ToLocalTime ();
729 public static DateTime SpecifyKind (DateTime value, DateTimeKind kind)
731 return new DateTime (value.Ticks, kind);
736 internal long ToBinary ()
741 internal static DateTime FromBinary (long dateData)
743 return new DateTime (dateData & 0x3fffffffffffffff);
747 public static int DaysInMonth (int year, int month)
751 if (month < 1 || month >12)
752 throw new ArgumentOutOfRangeException ();
754 if (year < 1 || year > 9999)
755 throw new ArgumentOutOfRangeException ();
757 days = (IsLeapYear(year) ? daysmonthleap : daysmonth);
761 public override bool Equals (object value)
763 if (!(value is System.DateTime))
766 return ((DateTime) value).ticks == ticks;
769 public static bool Equals (DateTime t1, DateTime t2 )
771 return (t1.ticks == t2.ticks );
774 public static DateTime FromFileTime (long fileTime)
777 throw new ArgumentOutOfRangeException ("fileTime", "< 0");
779 return new DateTime (w32file_epoch + fileTime).ToLocalTime ();
783 public static DateTime FromFileTimeUtc (long fileTime)
786 throw new ArgumentOutOfRangeException ("fileTime", "< 0");
788 return new DateTime (w32file_epoch + fileTime);
792 public static DateTime FromOADate (double d)
794 // An OLE Automation date is implemented as a floating-point number
795 // whose value is the number of days from midnight, 30 December 1899.
797 // d must be negative 657435.0 through positive 2958466.0.
798 if ((d <= OAMinValue) || (d >= OAMaxValue))
799 throw new ArgumentException ("d", "[-657435,2958466]");
801 DateTime dt = new DateTime (ticks18991230);
803 Double days = Math.Ceiling (d);
804 // integer part is the number of days (negative)
805 dt = dt.AddRoundedMilliseconds (days * 86400000);
806 // but decimals are the number of hours (in days fractions) and positive
807 Double hours = (days - d);
808 dt = dt.AddRoundedMilliseconds (hours * 86400000);
811 dt = dt.AddRoundedMilliseconds (d * 86400000);
817 public string[] GetDateTimeFormats()
819 return GetDateTimeFormats (CultureInfo.CurrentCulture);
822 public string[] GetDateTimeFormats(char format)
824 if ("dDgGfFmMrRstTuUyY".IndexOf (format) < 0)
825 throw new FormatException ("Invalid format character.");
826 string[] result = new string[1];
827 result[0] = this.ToString(format.ToString());
831 public string[] GetDateTimeFormats(IFormatProvider provider)
833 DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
834 // return GetDateTimeFormats (info.GetAllDateTimePatterns ());
835 ArrayList al = new ArrayList ();
836 foreach (char c in "dDgGfFmMrRstTuUyY")
837 al.AddRange (GetDateTimeFormats (c, info));
838 return al.ToArray (typeof (string)) as string [];
841 public string[] GetDateTimeFormats(char format,IFormatProvider provider )
843 if ("dDgGfFmMrRstTuUyY".IndexOf (format) < 0)
844 throw new FormatException ("Invalid format character.");
846 // LAMESPEC: There is NO assurance that 'U' ALWAYS
847 // euqals to 'F', but since we have to iterate all
848 // the pattern strings, we cannot just use
849 // ToString("U", provider) here. I believe that the
850 // method's behavior cannot be formalized.
851 bool adjustutc = false;
860 DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
861 return GetDateTimeFormats (adjustutc, info.GetAllRawDateTimePatterns (format), info);
864 private string [] GetDateTimeFormats (bool adjustutc, string [] patterns, DateTimeFormatInfo dfi)
866 string [] results = new string [patterns.Length];
867 DateTime val = adjustutc ? ToUniversalTime () : this;
868 for (int i = 0; i < results.Length; i++)
869 results [i] = DateTimeUtils.ToString (val, patterns [i], dfi);
874 private void CheckDateTimeKind (DateTimeKind kind) {
875 if ((kind != DateTimeKind.Unspecified) && (kind != DateTimeKind.Utc) && (kind != DateTimeKind.Local))
876 throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
880 public override int GetHashCode ()
882 return (int) ticks.Ticks;
885 public TypeCode GetTypeCode ()
887 return TypeCode.DateTime;
890 public static bool IsLeapYear (int year)
892 if (year < 1 || year > 9999)
893 throw new ArgumentOutOfRangeException ();
894 return ( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ;
897 public static DateTime Parse (string s)
899 return Parse (s, null);
902 public static DateTime Parse (string s, IFormatProvider provider)
904 return Parse (s, provider, DateTimeStyles.AllowWhiteSpaces);
907 public static DateTime Parse (string s, IFormatProvider provider, DateTimeStyles styles)
910 throw new ArgumentNullException ("s");
914 Exception exception = null;
915 if (!CoreParse (s, provider, styles, out res, out dto, true, ref exception))
921 const string formatExceptionMessage = "String was not recognized as a valid DateTime.";
923 internal static bool CoreParse (string s, IFormatProvider provider, DateTimeStyles styles,
924 out DateTime result, out DateTimeOffset dto, bool setExceptionOnError, ref Exception exception)
926 dto = new DateTimeOffset (0, TimeSpan.Zero);
927 if (s == null || s.Length == 0) {
928 if (setExceptionOnError)
929 exception = new FormatException (formatExceptionMessage);
934 if (provider == null)
935 provider = CultureInfo.CurrentCulture;
936 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
938 // Try first all the combinations of ParseAllDateFormats & ParseTimeFormats
939 string[] allDateFormats = YearMonthDayFormats (dfi, setExceptionOnError, ref exception);
940 if (allDateFormats == null){
945 bool longYear = false;
946 for (int i = 0; i < allDateFormats.Length; i++) {
947 string firstPart = allDateFormats [i];
948 bool incompleteFormat = false;
949 if (_DoParse (s, firstPart, "", false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
952 if (!incompleteFormat)
955 for (int j = 0; j < ParseTimeFormats.Length; j++) {
956 if (_DoParse (s, firstPart, ParseTimeFormats [j], false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
964 int dayIndex = dfi.MonthDayPattern.IndexOf('d');
965 int monthIndex = dfi.MonthDayPattern.IndexOf('M');
966 if (dayIndex == -1 || monthIndex == -1){
968 if (setExceptionOnError)
969 exception = new FormatException (Locale.GetText("Order of month and date is not defined by {0}", dfi.MonthDayPattern));
972 bool is_day_before_month = dayIndex < monthIndex;
973 string[] monthDayFormats = is_day_before_month ? DayMonthShortFormats : MonthDayShortFormats;
974 for (int i = 0; i < monthDayFormats.Length; i++) {
975 bool incompleteFormat = false;
976 if (_DoParse (s, monthDayFormats[i], "", false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
980 for (int j = 0; j < ParseTimeFormats.Length; j++) {
981 string firstPart = ParseTimeFormats [j];
982 bool incompleteFormat = false;
983 if (_DoParse (s, firstPart, "", false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
985 if (!incompleteFormat)
988 for (int i = 0; i < monthDayFormats.Length; i++) {
989 if (_DoParse (s, firstPart, monthDayFormats [i], false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
992 for (int i = 0; i < allDateFormats.Length; i++) {
993 string dateFormat = allDateFormats [i];
994 if (dateFormat[dateFormat.Length - 1] == 'T')
995 continue; // T formats must be before the time part
996 if (_DoParse (s, firstPart, dateFormat, false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
1001 // Try as a last resort all the patterns
1002 if (ParseExact (s, dfi.GetAllDateTimePatternsInternal (), dfi, styles, out result, false, ref longYear, setExceptionOnError, ref exception))
1005 if (!setExceptionOnError)
1009 // .NET 2.x does not throw an ArgumentOutOfRangeException, but .NET 1.1 does.
1010 exception = new FormatException (formatExceptionMessage);
1013 exception = new ArgumentOutOfRangeException ("year", "Valid values are between 1 and 9999, inclusive.");
1015 exception = new FormatException (formatExceptionMessage);
1020 public static DateTime ParseExact (string s, string format, IFormatProvider provider)
1022 return ParseExact (s, format, provider, DateTimeStyles.None);
1025 private static string[] YearMonthDayFormats (DateTimeFormatInfo dfi, bool setExceptionOnError, ref Exception exc)
1027 int dayIndex = dfi.ShortDatePattern.IndexOf('d');
1028 int monthIndex = dfi.ShortDatePattern.IndexOf('M');
1029 int yearIndex = dfi.ShortDatePattern.IndexOf('y');
1030 if (dayIndex == -1 || monthIndex == -1 || yearIndex == -1){
1031 if (setExceptionOnError)
1032 exc = new FormatException (Locale.GetText("Order of year, month and date is not defined by {0}", dfi.ShortDatePattern));
1036 if (yearIndex < monthIndex)
1037 if (monthIndex < dayIndex)
1038 return ParseYearMonthDayFormats;
1039 else if (yearIndex < dayIndex)
1040 return ParseYearDayMonthFormats;
1042 // The year cannot be between the date and the month
1043 if (setExceptionOnError)
1044 exc = new FormatException (Locale.GetText("Order of date, year and month defined by {0} is not supported", dfi.ShortDatePattern));
1047 else if (dayIndex < monthIndex)
1048 return ParseDayMonthYearFormats;
1049 else if (dayIndex < yearIndex)
1050 return ParseMonthDayYearFormats;
1052 // The year cannot be between the month and the date
1053 if (setExceptionOnError)
1054 exc = new FormatException (Locale.GetText("Order of month, year and date defined by {0} is not supported", dfi.ShortDatePattern));
1059 private static int _ParseNumber (string s, int valuePos,
1063 bool sloppy_parsing,
1069 leadingzero = false;
1072 int real_digits = 0;
1073 for (i = valuePos; i < s.Length && i < digits + valuePos; i++) {
1074 if (!Char.IsDigit (s[i]))
1080 digits = real_digits;
1082 if (digits < min_digits) {
1087 if (s.Length - valuePos < digits) {
1092 for (i = valuePos; i < digits + valuePos; i++) {
1094 if (!Char.IsDigit (c)) {
1099 number = number * 10 + (byte) (c - '0');
1102 num_parsed = digits;
1106 private static int _ParseEnum (string s, int sPos, string[] values, string[] invValues, bool exact, out int num_parsed)
1108 // FIXME: I know this is somehow lame code. Probably
1109 // it should iterate all the enum value and return
1110 // the longest match. However right now I don't see
1111 // anything but "1" and "10" - "12" that might match
1112 // two or more values. (They are only abbrev month
1113 // names, so do reverse order search). See bug #80094.
1114 for (int i = values.Length - 1; i >= 0; i--) {
1115 if (!exact && invValues [i].Length > values[i].Length) {
1116 if (invValues [i].Length > 0 && _ParseString (s, sPos, 0, invValues [i], out num_parsed))
1118 if (values [i].Length > 0 && _ParseString (s, sPos, 0, values [i], out num_parsed))
1122 if (values [i].Length > 0 && _ParseString (s, sPos, 0, values [i], out num_parsed))
1124 if (!exact && invValues [i].Length > 0 && _ParseString (s, sPos, 0, invValues [i], out num_parsed))
1133 private static bool _ParseString (string s, int sPos, int maxlength, string value, out int num_parsed)
1136 maxlength = value.Length;
1138 if (sPos + maxlength <= s.Length && String.Compare (s, sPos, value, 0, maxlength, true, CultureInfo.InvariantCulture) == 0) {
1139 num_parsed = maxlength;
1147 // Note that in case of Parse (exact == false) we check both for AM/PM
1148 // and the culture spcific AM/PM strings.
1149 private static bool _ParseAmPm(string s,
1152 DateTimeFormatInfo dfi,
1161 if (!IsLetter (s, valuePos)) {
1162 if (dfi.AMDesignator != "")
1169 DateTimeFormatInfo invInfo = DateTimeFormatInfo.InvariantInfo;
1170 if (!exact && _ParseString (s, valuePos, num, invInfo.PMDesignator, out num_parsed) ||
1171 dfi.PMDesignator != "" && _ParseString(s, valuePos, num, dfi.PMDesignator, out num_parsed))
1173 else if (!exact && _ParseString (s, valuePos, num, invInfo.AMDesignator, out num_parsed) ||
1174 _ParseString (s, valuePos, num, dfi.AMDesignator, out num_parsed)) {
1175 if (exact || num_parsed != 0)
1183 // Note that in case of Parse (exact == false) we check both for ':'
1184 // and the culture spcific TimeSperator
1185 private static bool _ParseTimeSeparator (string s, int sPos, DateTimeFormatInfo dfi, bool exact, out int num_parsed)
1187 return _ParseString (s, sPos, 0, dfi.TimeSeparator, out num_parsed) ||
1188 !exact && _ParseString (s, sPos, 0, ":", out num_parsed);
1191 // Accept any character for DateSeparator, except TimeSeparator,
1192 // a digit or a letter.
1193 // Not documented, but seems to be MS behaviour here. See bug 54047.
1194 private static bool _ParseDateSeparator (string s, int sPos, DateTimeFormatInfo dfi, bool exact, out int num_parsed)
1197 if (exact && s [sPos] != '/')
1200 if (_ParseTimeSeparator (s, sPos, dfi, exact, out num_parsed) ||
1201 Char.IsDigit (s [sPos]) || Char.IsLetter (s [sPos]))
1208 private static bool IsLetter (string s, int pos)
1210 return pos < s.Length && Char.IsLetter (s [pos]);
1213 // To implement better DateTime.Parse we use two format strings one
1214 // for Date and one for Time. This allows us to define two different
1215 // arrays of formats for Time and Dates and to combine them more or less
1216 // efficiently. When this mode is used flexibleTwoPartsParsing is true.
1217 private static bool _DoParse (string s,
1221 out DateTime result,
1222 out DateTimeOffset dto,
1223 DateTimeFormatInfo dfi,
1224 DateTimeStyles style,
1225 bool firstPartIsDate,
1226 ref bool incompleteFormat,
1229 bool useutc = false;
1230 bool use_invariant = false;
1231 bool sloppy_parsing = false;
1232 dto = new DateTimeOffset (0, TimeSpan.Zero);
1234 bool afterTimePart = firstPartIsDate && secondPart == "";
1236 bool flexibleTwoPartsParsing = !exact && secondPart != null;
1237 incompleteFormat = false;
1239 string format = firstPart;
1240 bool afterTFormat = false;
1241 DateTimeFormatInfo invInfo = DateTimeFormatInfo.InvariantInfo;
1242 if (format.Length == 1)
1243 format = DateTimeUtils.GetStandardPattern (format [0], dfi, out useutc, out use_invariant);
1245 result = new DateTime (0);
1249 if ((style & DateTimeStyles.AllowLeadingWhite) != 0) {
1250 format = format.TrimStart (null);
1252 s = s.TrimStart (null); // it could be optimized, but will make little good.
1255 if ((style & DateTimeStyles.AllowTrailingWhite) != 0) {
1256 format = format.TrimEnd (null);
1257 s = s.TrimEnd (null); // it could be optimized, but will make little good.
1263 if ((style & DateTimeStyles.AllowInnerWhite) != 0)
1264 sloppy_parsing = true;
1266 string chars = format;
1267 int len = format.Length, pos = 0, num = 0;
1271 int day = -1, dayofweek = -1, month = -1, year = -1;
1272 int hour = -1, minute = -1, second = -1;
1273 double fractionalSeconds = -1;
1275 int tzsign = -1, tzoffset = -1, tzoffmin = -1;
1276 bool isFirstPart = true;
1280 if (valuePos == s.Length)
1284 if (flexibleTwoPartsParsing && pos + num == 0)
1286 bool isLetter = IsLetter(s, valuePos);
1290 if (afterTimePart && isLetter) {
1292 if (s [valuePos] == 'Z')
1295 _ParseString (s, valuePos, 0, "GMT", out num_parsed);
1296 if (num_parsed > 0 && !IsLetter (s, valuePos + num_parsed)) {
1297 valuePos += num_parsed;
1302 if (!afterTFormat && _ParseAmPm (s, valuePos, 0, dfi, exact, out num_parsed, ref ampm)) {
1303 if (IsLetter (s, valuePos + num_parsed))
1305 else if (num_parsed > 0) {
1306 valuePos += num_parsed;
1311 if (!afterTFormat && dayofweek == -1 && isLetter) {
1312 dayofweek = _ParseEnum (s, valuePos, dfi.RawDayNames, invInfo.RawDayNames, exact, out num_parsed);
1313 if (dayofweek == -1)
1314 dayofweek = _ParseEnum (s, valuePos, dfi.RawAbbreviatedDayNames, invInfo.RawAbbreviatedDayNames, exact, out num_parsed);
1315 if (dayofweek != -1 && !IsLetter (s, valuePos + num_parsed)) {
1316 valuePos += num_parsed;
1323 if (char.IsWhiteSpace (s [valuePos]) || s [valuePos] == ',') {
1330 if (pos + num >= len)
1332 if (flexibleTwoPartsParsing && num == 0) {
1333 afterTFormat = isFirstPart && firstPart [firstPart.Length - 1] == 'T';
1334 if (!isFirstPart && format == "")
1339 format = secondPart;
1344 isFirstPart = false;
1346 if (!firstPartIsDate || format == "")
1347 afterTimePart = true;
1354 bool leading_zeros = true;
1356 if (chars[pos] == '\'') {
1358 while (pos+num < len) {
1359 if (chars[pos+num] == '\'')
1362 if (valuePos == s.Length || s [valuePos] != chars [pos + num])
1372 } else if (chars[pos] == '"') {
1374 while (pos+num < len) {
1375 if (chars[pos+num] == '"')
1378 if (valuePos == s.Length || s [valuePos] != chars[pos+num])
1388 } else if (chars[pos] == '\\') {
1393 if (s [valuePos] != chars [pos])
1399 } else if (chars[pos] == '%') {
1402 } else if (char.IsWhiteSpace (s [valuePos]) ||
1403 s [valuePos] == ',' && (!exact && chars [pos] == '/' || Char.IsWhiteSpace (chars [pos]))) {
1406 if (exact && (style & DateTimeStyles.AllowInnerWhite) == 0) {
1407 if (!Char.IsWhiteSpace (chars[pos]))
1414 while (ws < s.Length) {
1415 if (Char.IsWhiteSpace (s [ws]) || s [ws] == ',')
1422 while (ws < chars.Length) {
1423 if (Char.IsWhiteSpace (chars [ws]) || chars [ws] == ',')
1429 // A whitespace may match a '/' in the pattern.
1430 if (!exact && pos < chars.Length && chars[pos] == '/')
1431 if (!_ParseDateSeparator (s, valuePos, dfi, exact, out num_parsed))
1436 if ((pos+num+1 < len) && (chars[pos+num+1] == chars[pos+num])) {
1444 if (num < 2 && day != -1 || num >= 2 && dayofweek != -1)
1447 day = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1449 day = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1451 dayofweek = _ParseEnum (s, valuePos, dfi.RawAbbreviatedDayNames, invInfo.RawAbbreviatedDayNames, exact, out num_parsed);
1453 dayofweek = _ParseEnum (s, valuePos, dfi.RawDayNames, invInfo.RawDayNames, exact, out num_parsed);
1459 if (flexibleTwoPartsParsing) {
1461 if (num == 0 || num == 3)
1462 month = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1463 if (num > 1 && num_parsed == -1)
1464 month = _ParseEnum (s, valuePos, dfi.RawMonthNames, invInfo.RawMonthNames, exact, out num_parsed) + 1;
1465 if (num > 1 && num_parsed == -1)
1466 month = _ParseEnum (s, valuePos, dfi.RawAbbreviatedMonthNames, invInfo.RawAbbreviatedMonthNames, exact, out num_parsed) + 1;
1471 month = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1473 month = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1475 month = _ParseEnum (s, valuePos, dfi.RawAbbreviatedMonthNames, invInfo.RawAbbreviatedMonthNames, exact, out num_parsed) + 1;
1477 month = _ParseEnum (s, valuePos, dfi.RawMonthNames, invInfo.RawMonthNames, exact, out num_parsed) + 1;
1484 year = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1485 } else if (num < 3) {
1486 year = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1488 year = _ParseNumber (s, valuePos, exact ? 4 : 3, 4, false, sloppy_parsing, out num_parsed);
1489 if ((year >= 1000) && (num_parsed == 4) && (!longYear) && (s.Length > 4 + valuePos)) {
1491 int ly = _ParseNumber (s, valuePos, 5, 5, false, sloppy_parsing, out np);
1492 longYear = (ly > 9999);
1497 //FIXME: We should do use dfi.Calendat.TwoDigitYearMax
1498 if (num_parsed <= 2)
1499 year += (year < 30) ? 2000 : 1900;
1505 hour = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1507 hour = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1516 if (hour != -1 || !flexibleTwoPartsParsing && ampm >= 0)
1519 hour = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1521 hour = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1532 minute = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1534 minute = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1544 second = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1546 second = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1554 leading_zeros = false;
1558 if (num > 6 || fractionalSeconds != -1)
1560 double decimalNumber = (double) _ParseNumber (s, valuePos, 0, num+1, leading_zeros, sloppy_parsing, out num_parsed);
1561 if (num_parsed == -1)
1563 fractionalSeconds = decimalNumber / Math.Pow(10.0, num_parsed);
1566 if (!_ParseAmPm (s, valuePos, num > 0 ? 0 : 1, dfi, exact, out num_parsed, ref ampm))
1573 if (s [valuePos] == '+')
1575 else if (s [valuePos] == '-')
1582 tzoffset = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1584 tzoffset = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1586 tzoffset = _ParseNumber (s, valuePos, 1, 2, true, /*sloppy_parsing*/true, out num_parsed);
1587 valuePos += num_parsed;
1592 if (valuePos < s.Length && Char.IsDigit (s [valuePos]) ||
1593 _ParseTimeSeparator (s, valuePos, dfi, exact, out num_parsed)) {
1594 valuePos += num_parsed;
1595 tzoffmin = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1599 else if (!flexibleTwoPartsParsing)
1607 if (s [valuePos] == 'Z') {
1611 else if (s [valuePos] == '+' || s [valuePos] == '-') {
1614 if (s [valuePos] == '+')
1616 else if (s [valuePos] == '-')
1621 tzoffset = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1622 valuePos += num_parsed;
1626 if (Char.IsDigit (s [valuePos]))
1628 else if (!_ParseString (s, valuePos, 0, dfi.TimeSeparator, out num_parsed))
1630 valuePos += num_parsed;
1632 tzoffmin = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1639 // LAMESPEC: This should be part of UTCpattern
1640 // string and thus should not be considered here.
1642 // Note that 'Z' is not defined as a pattern
1643 // character. Keep it for X509 certificate
1644 // verification. Also, "Z" != "'Z'" under MS.NET
1645 // ("'Z'" is just literal; handled above)
1647 if (s [valuePos] != 'Z')
1654 if (s [valuePos] != 'G')
1657 if ((pos + 2 < len) && (valuePos + 2 < s.Length) &&
1658 (chars [pos + 1] == 'M') && (s[valuePos + 1] == 'M') &&
1659 (chars [pos + 2] == 'T') && (s[valuePos + 2] == 'T'))
1671 if (!_ParseTimeSeparator (s, valuePos, dfi, exact, out num_parsed))
1675 if (!_ParseDateSeparator (s, valuePos, dfi, exact, out num_parsed))
1681 if (s [valuePos] != chars [pos])
1692 valuePos += num_parsed;
1694 if (!exact && !flexibleTwoPartsParsing) {
1695 switch (chars [pos]) {
1703 if (s.Length > valuePos && s [valuePos] == 'Z' &&
1704 (pos + 1 == chars.Length || chars [pos + 1] != 'Z')) {
1712 pos = pos + num + 1;
1717 if (pos + 1 < len && chars [pos] == '.' && chars [pos + 1] == 'F') {
1719 while (pos < len && chars [pos] == 'F') // '.FFF....' can be mapped to nothing. See bug #444103
1722 while (pos < len && chars [pos] == 'K') // 'K' can be mapped to nothing
1728 if (s.Length > valuePos) // extraneous tail.
1733 if (Char.IsDigit (s [valuePos]) && Char.IsDigit (s [valuePos - 1]))
1735 if (Char.IsLetter (s [valuePos]) && Char.IsLetter (s [valuePos - 1]))
1737 incompleteFormat = true;
1748 if (fractionalSeconds == -1)
1749 fractionalSeconds = 0;
1751 // If no date was given
1752 if ((day == -1) && (month == -1) && (year == -1)) {
1753 if ((style & DateTimeStyles.NoCurrentDateDefault) != 0) {
1758 day = DateTime.Today.Day;
1759 month = DateTime.Today.Month;
1760 year = DateTime.Today.Year;
1769 if ((style & DateTimeStyles.NoCurrentDateDefault) != 0)
1772 year = DateTime.Today.Year;
1775 if (ampm == 0 && hour == 12)
1778 if (ampm == 1 && (!flexibleTwoPartsParsing || hour < 12))
1781 // For anything out of range
1783 if (year < 1 || year > 9999 ||
1784 month < 1 || month >12 ||
1785 day < 1 || day > DateTime.DaysInMonth(year, month) ||
1786 hour < 0 || hour > 23 ||
1787 minute < 0 || minute > 59 ||
1788 second < 0 || second > 59)
1791 result = new DateTime (year, month, day, hour, minute, second, 0);
1792 result = result.AddSeconds(fractionalSeconds);
1794 if (dayofweek != -1 && dayofweek != (int) result.DayOfWeek)
1798 if (result != DateTime.MinValue) {
1800 dto = new DateTimeOffset (result);
1801 } catch { } // We handle this error in DateTimeOffset.Parse
1809 tzoffset = -tzoffset;
1810 tzoffmin = -tzoffmin;
1813 dto = new DateTimeOffset (result, new TimeSpan (tzoffset, tzoffmin, 0));
1814 } catch {} // We handle this error in DateTimeOffset.Parse
1816 bool adjustToUniversal = (style & DateTimeStyles.AdjustToUniversal) != 0;
1819 long newticks = (result.ticks - dto.Offset).Ticks;
1821 newticks += TimeSpan.TicksPerDay;
1822 result = new DateTime (false, new TimeSpan (newticks));
1824 result.kind = DateTimeKind.Utc;
1825 if ((style & DateTimeStyles.RoundtripKind) != 0)
1826 result = result.ToLocalTime ();
1830 else if (useutc || ((style & DateTimeStyles.AssumeUniversal) != 0))
1831 result.kind = DateTimeKind.Utc;
1832 else if ((style & DateTimeStyles.AssumeLocal) != 0)
1833 result.kind = DateTimeKind.Local;
1835 bool adjustToLocal = !adjustToUniversal && (style & DateTimeStyles.RoundtripKind) == 0;
1836 if (result.kind != DateTimeKind.Unspecified)
1838 if (adjustToUniversal)
1839 result = result.ToUniversalTime ();
1840 else if (adjustToLocal)
1841 result = result.ToLocalTime ();
1844 if (!adjustToUniversal && (useutc || tzsign != -1))
1845 result = result.ToLocalTime ();
1850 public static DateTime ParseExact (string s, string format,
1851 IFormatProvider provider, DateTimeStyles style)
1854 throw new ArgumentNullException ("format");
1856 string [] formats = new string [1];
1857 formats[0] = format;
1859 return ParseExact (s, formats, provider, style);
1862 public static DateTime ParseExact (string s, string[] formats,
1863 IFormatProvider provider,
1864 DateTimeStyles style)
1866 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
1871 throw new ArgumentNullException ("s");
1872 if (formats == null)
1873 throw new ArgumentNullException ("formats");
1874 if (formats.Length == 0)
1875 throw new FormatException ("Format specifier was invalid.");
1878 bool longYear = false;
1880 if (!ParseExact (s, formats, dfi, style, out result, true, ref longYear, true, ref e))
1886 private static void CheckStyle (DateTimeStyles style)
1888 if ( (style & DateTimeStyles.RoundtripKind) != 0)
1890 if ((style & DateTimeStyles.AdjustToUniversal) != 0 || (style & DateTimeStyles.AssumeLocal) != 0 ||
1891 (style & DateTimeStyles.AssumeUniversal) != 0)
1892 throw new ArgumentException ("The DateTimeStyles value RoundtripKind cannot be used with the values AssumeLocal, Asersal or AdjustToUniversal.", "style");
1894 if ((style & DateTimeStyles.AssumeUniversal) != 0 && (style & DateTimeStyles.AssumeLocal) != 0)
1895 throw new ArgumentException ("The DateTimeStyles values AssumeLocal and AssumeUniversal cannot be used together.", "style");
1898 public static bool TryParse (string s, out DateTime result)
1902 Exception exception = null;
1905 return CoreParse (s, null, DateTimeStyles.AllowWhiteSpaces, out result, out dto, false, ref exception);
1912 public static bool TryParse (string s, IFormatProvider provider, DateTimeStyles styles, out DateTime result)
1916 Exception exception = null;
1919 return CoreParse (s, provider, styles, out result, out dto, false, ref exception);
1926 public static bool TryParseExact (string s, string format,
1927 IFormatProvider provider,
1928 DateTimeStyles style,
1929 out DateTime result)
1932 formats = new string [1];
1933 formats[0] = format;
1935 return TryParseExact (s, formats, provider, style, out result);
1938 public static bool TryParseExact (string s, string[] formats,
1939 IFormatProvider provider,
1940 DateTimeStyles style,
1941 out DateTime result)
1943 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
1945 bool longYear = false;
1947 return ParseExact (s, formats, dfi, style, out result, true, ref longYear, false, ref e);
1951 private static bool ParseExact (string s, string [] formats,
1952 DateTimeFormatInfo dfi, DateTimeStyles style, out DateTime ret,
1953 bool exact, ref bool longYear,
1954 bool setExceptionOnError, ref Exception exception)
1957 bool incompleteFormat = false;
1958 for (i = 0; i < formats.Length; i++)
1961 string format = formats[i];
1962 if (format == null || format == String.Empty)
1966 if (_DoParse (s, formats[i], null, exact, out result, out dto, dfi, style, false, ref incompleteFormat, ref longYear)) {
1972 if (setExceptionOnError)
1973 exception = new FormatException ("Invalid format string");
1974 ret = DateTime.MinValue;
1978 public TimeSpan Subtract (DateTime value)
1980 return new TimeSpan (ticks.Ticks) - value.ticks;
1983 public DateTime Subtract(TimeSpan value)
1987 newticks = (new TimeSpan (ticks.Ticks)) - value;
1988 DateTime ret = new DateTime (true,newticks);
1995 public long ToFileTime()
1997 DateTime universalTime = ToUniversalTime();
1999 if (universalTime.Ticks < w32file_epoch) {
2000 throw new ArgumentOutOfRangeException("file time is not valid");
2003 return(universalTime.Ticks - w32file_epoch);
2007 public long ToFileTimeUtc()
2009 if (Ticks < w32file_epoch) {
2010 throw new ArgumentOutOfRangeException("file time is not valid");
2013 return (Ticks - w32file_epoch);
2017 public string ToLongDateString()
2019 return ToString ("D");
2022 public string ToLongTimeString()
2024 return ToString ("T");
2027 public double ToOADate ()
2029 long t = this.Ticks;
2030 // uninitialized DateTime case
2033 // we can't reach minimum value
2034 if (t < 31242239136000000)
2035 return OAMinValue + 0.001;
2037 TimeSpan ts = new TimeSpan (this.Ticks - ticks18991230);
2038 double result = ts.TotalDays;
2039 // t < 0 (where 599264352000000000 == 0.0d for OA)
2040 if (t < 599264352000000000) {
2041 // negative days (int) but decimals are positive
2042 double d = Math.Ceiling (result);
2043 result = d - 2 - (result - d);
2046 // we can't reach maximum value
2047 if (result >= OAMaxValue)
2048 result = OAMaxValue - 0.00000001d;
2053 public string ToShortDateString()
2055 return ToString ("d");
2058 public string ToShortTimeString()
2060 return ToString ("t");
2063 public override string ToString ()
2065 return ToString ("G", null);
2068 public string ToString (IFormatProvider provider)
2070 return ToString (null, provider);
2073 public string ToString (string format)
2075 return ToString (format, null);
2078 public string ToString (string format, IFormatProvider provider)
2080 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
2082 if (format == null || format == String.Empty)
2085 bool useutc = false, use_invariant = false;
2087 if (format.Length == 1) {
2088 char fchar = format [0];
2089 format = DateTimeUtils.GetStandardPattern (fchar, dfi, out useutc, out use_invariant);
2091 return DateTimeUtils.ToString (ToUniversalTime (), format, dfi);
2092 // return ToUniversalTime()._ToString (format, dfi);
2095 throw new FormatException ("format is not one of the format specifier characters defined for DateTimeFormatInfo");
2098 // Don't convert UTC value. It just adds 'Z' for
2099 // 'u' format, for the same ticks.
2100 return DateTimeUtils.ToString (this, format, dfi);
2103 public DateTime ToLocalTime ()
2105 return TimeZone.CurrentTimeZone.ToLocalTime (this);
2108 public DateTime ToUniversalTime()
2110 return TimeZone.CurrentTimeZone.ToUniversalTime (this);
2115 public static DateTime operator +(DateTime d, TimeSpan t)
2117 DateTime ret = new DateTime (true, d.ticks + t);
2124 public static bool operator ==(DateTime d1, DateTime d2)
2126 return (d1.ticks == d2.ticks);
2129 public static bool operator >(DateTime t1,DateTime t2)
2131 return (t1.ticks > t2.ticks);
2134 public static bool operator >=(DateTime t1,DateTime t2)
2136 return (t1.ticks >= t2.ticks);
2139 public static bool operator !=(DateTime d1, DateTime d2)
2141 return (d1.ticks != d2.ticks);
2144 public static bool operator <(DateTime t1, DateTime t2)
2146 return (t1.ticks < t2.ticks );
2149 public static bool operator <=(DateTime t1,DateTime t2)
2151 return (t1.ticks <= t2.ticks);
2154 public static TimeSpan operator -(DateTime d1,DateTime d2)
2156 return new TimeSpan((d1.ticks - d2.ticks).Ticks);
2159 public static DateTime operator -(DateTime d,TimeSpan t)
2161 DateTime ret = new DateTime (true, d.ticks - t);
2168 bool IConvertible.ToBoolean(IFormatProvider provider)
2170 throw new InvalidCastException();
2173 byte IConvertible.ToByte(IFormatProvider provider)
2175 throw new InvalidCastException();
2179 char IConvertible.ToChar(IFormatProvider provider)
2181 throw new InvalidCastException();
2184 System.DateTime IConvertible.ToDateTime(IFormatProvider provider)
2189 decimal IConvertible.ToDecimal(IFormatProvider provider)
2191 throw new InvalidCastException();
2194 double IConvertible.ToDouble(IFormatProvider provider)
2196 throw new InvalidCastException();
2199 Int16 IConvertible.ToInt16(IFormatProvider provider)
2201 throw new InvalidCastException();
2204 Int32 IConvertible.ToInt32(IFormatProvider provider)
2206 throw new InvalidCastException();
2209 Int64 IConvertible.ToInt64(IFormatProvider provider)
2211 throw new InvalidCastException();
2215 #pragma warning disable 3019
2216 [CLSCompliant (false)]
2218 SByte IConvertible.ToSByte(IFormatProvider provider)
2220 throw new InvalidCastException();
2223 #pragma warning restore 3019
2226 Single IConvertible.ToSingle(IFormatProvider provider)
2228 throw new InvalidCastException();
2231 object IConvertible.ToType (Type type, IFormatProvider provider)
2234 throw new ArgumentNullException ("type");
2236 if (type == typeof (DateTime))
2238 else if (type == typeof (String))
2239 return this.ToString (provider);
2240 else if (type == typeof (Object))
2243 throw new InvalidCastException();
2247 #pragma warning disable 3019
2248 [CLSCompliant (false)]
2250 UInt16 IConvertible.ToUInt16(IFormatProvider provider)
2252 throw new InvalidCastException();
2255 #pragma warning restore 3019
2259 #pragma warning disable 3019
2260 [CLSCompliant (false)]
2262 UInt32 IConvertible.ToUInt32(IFormatProvider provider)
2264 throw new InvalidCastException();
2267 #pragma warning restore 3019
2271 #pragma warning disable 3019
2272 [CLSCompliant (false)]
2274 UInt64 IConvertible.ToUInt64(IFormatProvider provider)
2276 throw new InvalidCastException();
2279 #pragma warning restore 3019