2004-10-17 Ben Maurer <bmaurer@ximian.com>
[mono.git] / mcs / class / corlib / System / DateTime.cs
index 9bd14a37a2ec5608a60667228c3fc03b6db1adff..2acbd6dd683b2b5cb5f00078b232898cefd9f75f 100644 (file)
-//\r
-// System.DateTime.cs\r
-//\r
-// author:\r
-//   Marcel Narings (marcel@narings.nl)\r
-//   Martin Baulig (martin@gnome.org)\r
-//\r
-//   (C) 2001 Marcel Narings\r
-\r
-using System;\r
-using System.Globalization;\r
-using System.Runtime.CompilerServices;\r
-\r
-\r
-namespace System\r
-{\r
-       /// <summary>\r
-       /// The DateTime structure represents dates and time ranging from\r
-       /// 1-1-0001 12:00:00 AM to 31-12-9999 23:59:00 Common Era.\r
-       /// </summary>\r
-       /// \r
-       [Serializable]\r
-       public struct DateTime : IComparable , IFormattable  , IConvertible\r
-       {\r
-               private TimeSpan ticks;\r
-\r
-               private const int dp400 = 146097;\r
-               private const int dp100 = 36524;\r
-               private const int dp4 = 1461;\r
-\r
-               // w32 file time starts counting from 1/1/1601 00:00 GMT\r
-               // which is the constant ticks from the .NET epoch\r
-               private const long w32file_epoch = 504911232000000000L;\r
-\r
-               //\r
-               // The UnixEpoch, it begins on Jan 1, 1970 at 0:0:0, expressed\r
-               // in Ticks\r
-               //\r
-               internal const long UnixEpoch = 621355968000000000L;\r
-               \r
-               public static readonly DateTime MaxValue = new DateTime (false,TimeSpan.MaxValue);\r
-               public static readonly DateTime MinValue = new DateTime (false,TimeSpan.MinValue);\r
-               \r
-               private enum Which \r
-               {\r
-                       Day,\r
-                       DayYear,\r
-                       Month,\r
-                       Year\r
-               };\r
-       \r
-               private static int[] daysmonth = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; \r
-               private static int[] daysmonthleap = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };     \r
-\r
-               private static int AbsoluteDays (int year, int month, int day)\r
-               {\r
-                       int[] days;\r
-                       int temp = 0, m=1 ;\r
-               \r
-                       days = (IsLeapYear(year) ? daysmonthleap  : daysmonth);\r
-                       \r
-                       while (m < month)\r
-                               temp += days[m++];\r
-                       return ((day-1) + temp + (365* (year-1)) + ((year-1)/4) - ((year-1)/100) + ((year-1)/400));\r
-               }\r
-\r
-               private int FromTicks(Which what)\r
-               {\r
-                       int num400, num100, num4, numyears; \r
-                       int M =1;\r
-\r
-                       int[] days = daysmonth;\r
-                       int totaldays = this.ticks.Days;\r
-\r
-                       num400 = (totaldays / dp400);\r
-                       totaldays -=  num400 * dp400;\r
-               \r
-                       num100 = (totaldays / dp100);\r
-                       if (num100 == 4)   // leap\r
-                               num100 = 3;\r
-                       totaldays -= (num100 * dp100);\r
-\r
-                       num4 = totaldays / dp4;\r
-                       totaldays -= (num4 * dp4);\r
-\r
-                       numyears = totaldays / 365 ;\r
-\r
-                       if (numyears == 4)  //leap\r
-                               numyears =3 ;\r
-                       if (what == Which.Year )\r
-                               return num400*400 + num100*100 + num4*4 + numyears + 1;\r
-\r
-                       totaldays -= (numyears * 365) ;\r
-                       if (what == Which.DayYear )\r
-                               return totaldays + 1;\r
-                       \r
-                       if  ((numyears==3) && ((num100 == 3) || !(num4 == 24)) ) //31 dec leapyear\r
-                               days = daysmonthleap;\r
-                               \r
-                       while (totaldays >= days[M])\r
-                               totaldays -= days[M++];\r
-\r
-                       if (what == Which.Month )\r
-                               return M;\r
-\r
-                       return totaldays +1; \r
-               }\r
-\r
-\r
-               // Constructors\r
-               \r
-               /// <summary>\r
-               /// Constructs a DateTime for specified ticks\r
-               /// </summary>\r
-               /// \r
-               public DateTime (long newticks)\r
-                       // `local' must default to false here to avoid\r
-                       // a recursion loop.\r
-                       : this (false, newticks) {}\r
-\r
-               internal DateTime (bool local, long newticks)\r
-                       : this (true, new TimeSpan (newticks))\r
-               {\r
-                       if (local) {\r
-                               TimeZone tz = TimeZone.CurrentTimeZone;\r
-\r
-                               TimeSpan utcoffset = tz.GetUtcOffset (this);\r
-\r
-                               ticks = ticks + utcoffset;\r
-                       }\r
-               }\r
-\r
-               public DateTime (int year, int month, int day)\r
-                       : this (year, month, day,0,0,0,0) {}\r
-\r
-               public DateTime (int year, int month, int day, int hour, int minute, int second)\r
-                       : this (year, month, day, hour, minute, second, 0)      {}\r
-\r
-               public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond)\r
-                       {\r
-                       if ( year < 1 || year > 9999 || \r
-                               month < 1 || month >12  ||\r
-                               day < 1 || day > DaysInMonth(year, month) ||\r
-                               hour < 0 || hour > 23 ||\r
-                               minute < 0 || minute > 59 ||\r
-                               second < 0 || second > 59 )\r
-                               throw new ArgumentOutOfRangeException ("Parameters describe an " +\r
-                                                                       "unrepresentable DateTime.");\r
-\r
-                       ticks = new TimeSpan (AbsoluteDays(year,month,day), hour, minute, second, millisecond);\r
-               }\r
-\r
-               public DateTime (int year, int month, int day, Calendar calendar)\r
-                       : this (year, month, day, 0, 0, 0, 0, calendar) {}\r
-\r
-               \r
-               public DateTime (int year, int month, int day, int hour, int minute, int second, Calendar calendar)\r
-                       : this (year, month, day, hour, minute, second, 0, calendar)    {}\r
-\r
-\r
-               public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar)\r
-                       : this (year, month, day, hour, minute, second, millisecond) \r
-               {\r
-                       if (calendar == null)\r
-                               throw new ArgumentNullException();\r
-               }\r
-\r
-               internal DateTime (bool check, TimeSpan value)\r
-               {\r
-                       if (check && (value.Ticks < MinValue.Ticks || value.Ticks > MaxValue.Ticks))\r
-                               throw new ArgumentOutOfRangeException ();\r
-\r
-                       ticks = value;\r
-               }\r
-\r
-               /* Properties  */\r
-                \r
-               public DateTime Date \r
-               {\r
-                       get     \r
-                       { \r
-                               return new DateTime (Year, Month, Day);\r
-                       }\r
-               }\r
-        \r
-               public int Month \r
-               {\r
-                       get     \r
-                       { \r
-                               return FromTicks(Which.Month); \r
-                       }\r
-               }\r
-\r
-              \r
-               public int Day\r
-               {\r
-                       get \r
-                       { \r
-                               return FromTicks(Which.Day); \r
-                       }\r
-               }\r
-\r
-               public DayOfWeek DayOfWeek \r
-               {\r
-                       get \r
-                       { \r
-                               return ( (DayOfWeek) ((ticks.Days+1) % 7) ); \r
-                       }\r
-               }\r
-\r
-               public int DayOfYear \r
-               {\r
-                       get \r
-                       { \r
-                               return FromTicks(Which.DayYear); \r
-                       }\r
-               }\r
-\r
-               public TimeSpan TimeOfDay \r
-               {\r
-                       get     \r
-                       { \r
-                               return new TimeSpan(ticks.Ticks % TimeSpan.TicksPerDay );\r
-                       }\r
-                       \r
-               }\r
-\r
-               public int Hour \r
-               {\r
-                       get \r
-                       { \r
-                               return ticks.Hours;\r
-                       }\r
-               }\r
-\r
-               public int Minute \r
-               {\r
-                       get \r
-                       { \r
-                               return ticks.Minutes;\r
-                       }\r
-               }\r
-\r
-               public int Second \r
-               {\r
-                       get     \r
-                       { \r
-                               return ticks.Seconds;\r
-                       }\r
-               }\r
-\r
-               public int Millisecond \r
-               {\r
-                       get \r
-                       { \r
-                               return ticks.Milliseconds;\r
-                       }\r
-               }\r
-               \r
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]\r
-               internal static extern long GetNow ();\r
-\r
-               public static DateTime Now \r
-               {\r
-                       get     \r
-                       {\r
-                               return new DateTime (true, GetNow ());\r
-                       }\r
-               }\r
-\r
-               public long Ticks\r
-               { \r
-                       get     \r
-                       { \r
-                               return ticks.Ticks;\r
-                       }\r
-               }\r
-       \r
-               public static DateTime Today \r
-               {\r
-                       get     \r
-                       {\r
-                               return new DateTime (false, (GetNow () / TimeSpan.TicksPerDay) * TimeSpan.TicksPerDay);\r
-                       }\r
-               }\r
-\r
-               public static DateTime UtcNow \r
-               {\r
-                       get {\r
-                               return new DateTime (GetNow ());\r
-                       }\r
-               }\r
-\r
-               public int Year \r
-               {\r
-                       get \r
-                       { \r
-                               return FromTicks(Which.Year); \r
-                       }\r
-               }\r
-\r
-               /* methods */\r
-\r
-               public DateTime Add (TimeSpan ts)\r
-               {\r
-                       return new DateTime (true, ticks) + ts;\r
-               }\r
-\r
-               public DateTime AddDays (double days)\r
-               {\r
-                       return AddMilliseconds (days * 86400000);\r
-               }\r
-               \r
-               public DateTime AddTicks (long t)\r
-               {\r
-                       return Add (new TimeSpan (t));\r
-               }\r
-\r
-               public DateTime AddHours (double hours)\r
-               {\r
-                       return AddMilliseconds (hours * 3600000);\r
-               }\r
-\r
-               public DateTime AddMilliseconds (double ms)\r
-               {\r
-                       long msticks;\r
-                       \r
-                       msticks = (long) (ms += ms > 0 ? 0.5 : -0.5) * TimeSpan.TicksPerMillisecond ; \r
-\r
-                       return AddTicks (msticks);\r
-               }\r
-\r
-               public DateTime AddMinutes (double minutes)\r
-               {\r
-                       return AddMilliseconds (minutes * 60000);\r
-               }\r
-               \r
-               public DateTime AddMonths (int months)\r
-               {\r
-                       int day, month, year,  maxday ;\r
-                       DateTime temp ;\r
-\r
-                       day = this.Day;\r
-                       month = this.Month + (months % 12);\r
-                       year = this.Year + months/12 ;\r
-                       \r
-                       if (month < 1)\r
-                       {\r
-                               month = 12 + month ;\r
-                               year -- ;\r
-                       }\r
-                       else if (month>12) \r
-                       {\r
-                               month = month -12;\r
-                               year ++;\r
-                       }\r
-                       maxday = DaysInMonth(year, month);\r
-                       if (day > maxday)\r
-                               day = maxday;\r
-\r
-                       temp = new DateTime (year, month, day);\r
-                       return  temp.Add (this.TimeOfDay);\r
-               }\r
-\r
-               public DateTime AddSeconds (double seconds)\r
-               {\r
-                       return AddMilliseconds (seconds*1000);\r
-               }\r
-\r
-               public DateTime AddYears (int years )\r
-               {\r
-                       return AddMonths(years * 12);\r
-               }\r
-\r
-               public static int Compare (DateTime t1, DateTime t2)\r
-               {\r
-                       if (t1.ticks < t2.ticks) \r
-                               return -1;\r
-                       else if (t1.ticks > t2.ticks) \r
-                               return 1;\r
-                       else\r
-                               return 0;\r
-               }\r
-\r
-               public int CompareTo (object v)\r
-               {\r
-                       if ( v == null)\r
-                               return 1;\r
-\r
-                       if (!(v is System.DateTime))\r
-                               throw new ArgumentException (Locale.GetText (\r
-                                       "Value is not a System.DateTime"));\r
-\r
-                       return Compare (this, (DateTime) v);\r
-               }\r
-\r
-               public static int DaysInMonth (int year, int month)\r
-               {\r
-                       int[] days ;\r
-\r
-                       if (month < 1 || month >12)\r
-                               throw new ArgumentOutOfRangeException ();\r
-\r
-                       days = (IsLeapYear(year) ? daysmonthleap  : daysmonth);\r
-                       return days[month];                     \r
-               }\r
-               \r
-               public override bool Equals (object o)\r
-               {\r
-                       if (!(o is System.DateTime))\r
-                               return false;\r
-\r
-                       return ((DateTime) o).ticks == ticks;\r
-               }\r
-\r
-               public static bool Equals (DateTime t1, DateTime t2 )\r
-               {\r
-                       return (t1.ticks == t2.ticks );\r
-               }\r
-\r
-               public static DateTime FromFileTime (long fileTime) \r
-               {\r
-                       return new DateTime (w32file_epoch + fileTime);\r
-               }\r
-\r
-               // TODO: Implement me.\r
-               [MonoTODO]\r
-               public static DateTime FromOADate (double d)\r
-               {\r
-                               return new DateTime(0);\r
-               }\r
-               \r
-               // TODO: Implement me.\r
-               [MonoTODO]\r
-               public string[] GetDateTimeFormats() \r
-               {\r
-                       return null;\r
-               }\r
-\r
-               //TODO: implement me\r
-               [MonoTODO]\r
-               public string[] GetDateTimeFormats(char format)\r
-               {\r
-                       return null;\r
-               }\r
-               \r
-               // TODO: implement me\r
-               [MonoTODO]\r
-               public string[] GetDateTimeFormats(IFormatProvider provider)\r
-               {\r
-                       return null;\r
-               }\r
-\r
-               //TODO: implement me \r
-               [MonoTODO]\r
-               public string[] GetDateTimeFormats(char format,IFormatProvider provider )\r
-               {\r
-                       return null;\r
-               }\r
-\r
-               public override int GetHashCode ()\r
-               {\r
-                       return (int) ticks.Ticks;\r
-               }\r
-\r
-               public TypeCode GetTypeCode ()\r
-               {\r
-                       return TypeCode.DateTime;\r
-               }\r
-\r
-               public static bool IsLeapYear (int year)\r
-               {\r
-                       return  ( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ;\r
-               }\r
-\r
-               public static DateTime Parse (string s)\r
-               {\r
-                       return Parse (s, null);\r
-               }\r
-\r
-               public static DateTime Parse (string s, IFormatProvider fp)\r
-               {\r
-                       return Parse (s, null, DateTimeStyles.AllowWhiteSpaces);\r
-               }\r
-\r
-               public static DateTime Parse (string s, IFormatProvider fp, DateTimeStyles styles)\r
-               {\r
-                       string[] formats = {\r
-                               // Full date and time\r
-                               "F", "G", "r", "s", "u", "U",\r
-                               // Full date and time, but no seconds\r
-                               "f", "g",\r
-                               // Only date\r
-                               "d", "D",\r
-                               // Only time\r
-                               "T", "t",\r
-                               // Only date, but no year\r
-                               "m",\r
-                               // Only date, but no day\r
-                               "y" \r
-                       };\r
-\r
-                       return ParseExact (s, formats, fp, styles);\r
-               }\r
-\r
-               public static DateTime ParseExact (string s, string format, IFormatProvider fp)\r
-               {\r
-                       return ParseExact (s, format, fp, DateTimeStyles.None);\r
-               }\r
-\r
-               internal static int _ParseNumber (string s, int digits, bool leadingzero,\r
-                                                 bool sloppy_parsing, out int num_parsed)\r
-               {\r
-                       int number = 0, i;\r
-\r
-                       if (sloppy_parsing)\r
-                               leadingzero = false;\r
-\r
-                       if (!leadingzero) {\r
-                               int real_digits = 0;\r
-                               for (i = 0; i < s.Length; i++) {\r
-                                       if (!Char.IsDigit (s[i]))\r
-                                               break;\r
-\r
-                                       real_digits++;\r
-                               }\r
-\r
-                               digits = real_digits;\r
-                       }\r
-\r
-                       if (s.Length < digits) {\r
-                               num_parsed = -1;\r
-                               return 0;\r
-                       }\r
-\r
-                       for (i = 0; i < digits; i++) {\r
-                               char c = s[i];\r
-                               if (!Char.IsDigit (c)) {\r
-                                       num_parsed = -1;\r
-                                       return 0;\r
-                               }\r
-\r
-                               number = number * 10 + (byte) (c - '0');\r
-                       }\r
-\r
-                       num_parsed = digits;\r
-                       return number;\r
-               }\r
-\r
-               internal static int _ParseEnum (string s, string[] values, out int num_parsed)\r
-               {\r
-                       int i;\r
-\r
-                       for (i = 0; i < values.Length; i++) {\r
-                               if (s.Length < values[i].Length)\r
-                                       continue;\r
-                               String tmp = s.Substring (0, values[i].Length);\r
-                               if (String.Compare (tmp, values[i], true) == 0) {\r
-                                       num_parsed = values[i].Length;\r
-                                       return i;\r
-                               }\r
-                       }\r
-\r
-                       num_parsed = -1;\r
-                       return -1;\r
-               }\r
-\r
-               internal static bool _ParseString (string s, int maxlength, string value, out int num_parsed)\r
-               {\r
-                       if (maxlength > 0)\r
-                               value = value.Substring (0, maxlength);\r
-\r
-                       s = s.Substring (0, value.Length);\r
-\r
-                       if (String.Compare (s, value, true) == 0) {\r
-                               num_parsed = value.Length;\r
-                               return true;\r
-                       }\r
-\r
-                       num_parsed = -1;\r
-                       return false;\r
-               }\r
-\r
-               internal static bool _DoParse (string s, string format, bool exact,\r
-                                              out DateTime result,\r
-                                              DateTimeFormatInfo dfi,\r
-                                              DateTimeStyles style)\r
-               {\r
-                       bool useutc = false, use_localtime = true;\r
-                       bool sloppy_parsing = false;\r
-\r
-                       if (format.Length == 1)\r
-                               format = _GetStandardPattern (format[0], dfi, out useutc);\r
-\r
-                       if ((style & DateTimeStyles.AllowLeadingWhite) != 0) {\r
-                               format = format.TrimStart (null);\r
-                               s = s.TrimStart (null);\r
-                       }\r
-\r
-                       if ((style & DateTimeStyles.AllowTrailingWhite) != 0) {\r
-                               format = format.TrimEnd (null);\r
-                               s = s.TrimEnd (null);\r
-                       }\r
-\r
-                       if ((style & DateTimeStyles.AllowInnerWhite) != 0)\r
-                               sloppy_parsing = true;\r
-\r
-                       char[] chars = format.ToCharArray ();\r
-                       int len = format.Length, pos = 0, num = 0;\r
-\r
-                       int day = -1, dayofweek = -1, month = -1, year = -1;\r
-                       int hour = -1, minute = -1, second = -1, millisecond = -1;\r
-                       int ampm = -1;\r
-                       int tzsign = -1, tzoffset = -1, tzoffmin = -1;\r
-\r
-                       result = new DateTime (0);\r
-                       while (pos+num < len)\r
-                       {\r
-                               if (s.Length == 0)\r
-                                       break;\r
-\r
-                               if (Char.IsWhiteSpace (s[0])) {\r
-                                       s = s.Substring (1);\r
-\r
-                                       if (Char.IsWhiteSpace (chars[pos])) {\r
-                                               pos++;\r
-                                               continue;\r
-                                       }\r
-\r
-                                       if ((style & DateTimeStyles.AllowInnerWhite) == 0)\r
-                                               return false;\r
-                               }\r
-\r
-                               if (chars[pos] == '\'') {\r
-                                       num = 1;\r
-                                       while (pos+num < len) {\r
-                                               if (chars[pos+num] == '\'')\r
-                                                       break;\r
-\r
-                                               if (s.Length == 0)\r
-                                                       return false;\r
-                                               if (s[0] != chars[pos+num])\r
-                                                       return false;\r
-                                               s = s.Substring (1);\r
-\r
-                                               num++;\r
-                                       }\r
-                                       if (pos+num > len)\r
-                                               return false;\r
-\r
-                                       pos += num + 1;\r
-                                       num = 0;\r
-                                       continue;\r
-                               } else if (chars[pos] == '\\') {\r
-                                       if (pos+1 >= len)\r
-                                               return false;\r
-\r
-                                       if (s[0] != chars[pos+num])\r
-                                               return false;\r
-                                       s = s.Substring (1);\r
-                                       if (s.Length == 0)\r
-                                               return false;\r
-\r
-                                       pos++;\r
-                                       continue;\r
-                               } else if (chars[pos] == '%') {\r
-                                       pos++;\r
-                                       continue;\r
-                               }\r
-\r
-                               if ((pos+num+1 < len) && (chars[pos+num+1] == chars[pos+num])) {\r
-                                       num++;\r
-                                       continue;\r
-                               }\r
-\r
-                               int num_parsed = 0;\r
-\r
-                               switch (chars[pos])\r
-                               {\r
-                               case 'd':\r
-                                       if (day != -1)\r
-                                               return false;\r
-                                       if (num == 0)\r
-                                               day = _ParseNumber (s, 2, false, sloppy_parsing, out num_parsed);\r
-                                       else if (num == 1)\r
-                                               day = _ParseNumber (s, 2, true, sloppy_parsing, out num_parsed);\r
-                                       else if (num == 2)\r
-                                               dayofweek = _ParseEnum (s, dfi.AbbreviatedDayNames, out num_parsed);\r
-                                       else\r
-                                       {\r
-                                               dayofweek = _ParseEnum (s, dfi.DayNames, out num_parsed);\r
-                                               num = 3;\r
-                                       }\r
-                                       break;\r
-                               case 'M':\r
-                                       if (month != -1)\r
-                                               return false;\r
-                                       if (num == 0)\r
-                                               month = _ParseNumber (s, 2, false, sloppy_parsing, out num_parsed);\r
-                                       else if (num == 1)\r
-                                               month = _ParseNumber (s, 2, true, sloppy_parsing, out num_parsed);\r
-                                       else if (num == 2)\r
-                                               month = _ParseEnum (s, dfi.AbbreviatedMonthNames , out num_parsed) + 1;\r
-                                       else\r
-                                       {\r
-                                               month = _ParseEnum (s, dfi.MonthNames, out num_parsed) + 1;\r
-                                               num = 3;\r
-                                       }\r
-                                       break;\r
-                               case 'y':\r
-                                       if (year != -1)\r
-                                               return false;\r
-                                       if (num == 0) {\r
-                                               year = _ParseNumber (s, 2, false, sloppy_parsing, out num_parsed);\r
-                                               year += (year < 30) ? 2000 : 1900;\r
-                                       } else if (num < 3) {\r
-                                               year = _ParseNumber (s, 2, true, sloppy_parsing, out num_parsed);\r
-                                               year += (year < 30) ? 2000 : 1900;\r
-                                       } else {\r
-                                               year = _ParseNumber (s, 4, false, sloppy_parsing, out num_parsed);\r
-                                               num = 3;\r
-                                       }\r
-                                       \r
-                                       if (year != 0 && (year < 1 || year > 9999))\r
-                                               throw new ArgumentOutOfRangeException ("year", "Valid " + \r
-                                                               "values are between 1 and 9999 inclusive");\r
-                                       break;\r
-                               case 'h':\r
-                                       if (hour != -1)\r
-                                               return false;\r
-                                       if (num == 0)\r
-                                               hour = _ParseNumber (s, 2, false, sloppy_parsing, out num_parsed);\r
-                                       else\r
-                                       {\r
-                                               hour = _ParseNumber (s, 2, true, sloppy_parsing, out num_parsed);\r
-                                               num = 1;\r
-                                       }\r
-\r
-                                       if (hour >= 12)\r
-                                               return false;\r
-\r
-                                       break;\r
-                               case 'H':\r
-                                       if ((hour != -1) || (ampm >= 0))\r
-                                               return false;\r
-                                       if (num == 0)\r
-                                               hour = _ParseNumber (s, 2, false, sloppy_parsing, out num_parsed);\r
-                                       else\r
-                                       {\r
-                                               hour = _ParseNumber (s, 2, true, sloppy_parsing, out num_parsed);\r
-                                               num = 1;\r
-                                       }\r
-                                       if (hour >= 24)\r
-                                               return false;\r
-\r
-                                       ampm = -2;\r
-                                       break;\r
-                               case 'm':\r
-                                       if (minute != -1)\r
-                                               return false;\r
-                                       if (num == 0)\r
-                                               minute = _ParseNumber (s, 2, false, sloppy_parsing, out num_parsed);\r
-                                       else\r
-                                       {\r
-                                               minute = _ParseNumber (s, 2, true, sloppy_parsing, out num_parsed);\r
-                                               num = 1;\r
-                                       }\r
-                                       if (minute >= 60)\r
-                                               return false;\r
-\r
-                                       break;\r
-                               case 's':\r
-                                       if (second != -1)\r
-                                               return false;\r
-                                       if (num == 0)\r
-                                               second = _ParseNumber (s, 2, false, sloppy_parsing, out num_parsed);\r
-                                       else\r
-                                       {\r
-                                               second = _ParseNumber (s, 2, true, sloppy_parsing, out num_parsed);\r
-                                               num = 1;\r
-                                       }\r
-                                       if (second >= 60)\r
-                                               return false;\r
-\r
-                                       break;\r
-                               case 'f':\r
-                                       if (millisecond != -1)\r
-                                               return false;\r
-                                       num = Math.Min (num, 6);\r
-                                       millisecond = _ParseNumber (s, num+1, true, sloppy_parsing, out num_parsed);\r
-                                       if (millisecond >= 1000)\r
-                                               return false;\r
-                                       break;\r
-                               case 't':\r
-                                       if (ampm != -1)\r
-                                               return false;\r
-                                       if (num == 0)\r
-                                       {\r
-                                               if (_ParseString (s, 1, dfi.AMDesignator, out num_parsed))\r
-                                                       ampm = 0;\r
-                                               else if (_ParseString (s, 1, dfi.PMDesignator, out num_parsed))\r
-                                                       ampm = 1;\r
-                                               else\r
-                                                       return false;\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               if (_ParseString (s, 0, dfi.AMDesignator, out num_parsed))\r
-                                                       ampm = 0;\r
-                                               else if (_ParseString (s, 0, dfi.PMDesignator, out num_parsed))\r
-                                                       ampm = 1;\r
-                                               else\r
-                                                       return false;\r
-                                               num = 1;\r
-                                       }\r
-                                       break;\r
-                               case 'z':\r
-                                       if (tzsign != -1)\r
-                                               return false;\r
-                                       if (s[0] == '+')\r
-                                               tzsign = 0;\r
-                                       else if (s[0] == '-')\r
-                                               tzsign = 1;\r
-                                       else\r
-                                               return false;\r
-                                       s = s.Substring (1);\r
-                                       if (num == 0)\r
-                                               tzoffset = _ParseNumber (s, 2, false, sloppy_parsing, out num_parsed);\r
-                                       else if (num == 1)\r
-                                               tzoffset = _ParseNumber (s, 2, true, sloppy_parsing, out num_parsed);\r
-                                       else\r
-                                       {\r
-                                               tzoffset = _ParseNumber (s, 2, true, sloppy_parsing, out num_parsed);\r
-                                               if (num_parsed < 0)\r
-                                                       return false;\r
-                                               s = s.Substring (num_parsed);\r
-                                               if (!_ParseString (s, 0, dfi.TimeSeparator, out num_parsed))\r
-                                                       return false;\r
-                                               s = s.Substring (num_parsed);\r
-                                               tzoffmin = _ParseNumber (s, 2, true, sloppy_parsing, out num_parsed);\r
-                                               if (num_parsed < 0)\r
-                                                       return false;\r
-                                               num = 2;\r
-                                       }\r
-                                       break;\r
-                               case ':':\r
-                                       if (!_ParseString (s, 0, dfi.TimeSeparator, out num_parsed))\r
-                                               return false;\r
-                                       break;\r
-                               case '/':\r
-                                       if (!_ParseString (s, 0, dfi.DateSeparator, out num_parsed))\r
-                                               return false;\r
-                                       break;\r
-                               default:\r
-                                       if (s[0] != chars[pos])\r
-                                               return false;\r
-                                       num = 0;\r
-                                       num_parsed = 1;\r
-                                       break;\r
-                               }\r
-\r
-                               if (num_parsed < 0)\r
-                                       return false;\r
-\r
-                               s = s.Substring (num_parsed);\r
-\r
-                               pos = pos + num + 1;\r
-                               num = 0;\r
-                       }\r
-\r
-                       if (hour == -1)\r
-                               hour = 0;\r
-                       if (minute == -1)\r
-                               minute = 0;\r
-                       if (second == -1)\r
-                               second = 0;\r
-                       if (millisecond == -1)\r
-                               millisecond = 0;\r
-\r
-                       // If no date was given\r
-                       if ((day == -1) && (month == -1) && (year == -1)) {\r
-                               if ((style & DateTimeStyles.NoCurrentDateDefault) != 0) {\r
-                                       day = 1;\r
-                                       month = 1;\r
-                                       year = 1;\r
-                               } else {\r
-                                       day = Today.Day;\r
-                                       month = Today.Month;\r
-                                       year = Today.Year;\r
-                               }\r
-                       }\r
-\r
-                       if (day == -1)\r
-                               day = 1;\r
-                       if (month == -1)\r
-                               month = 1;\r
-                       if (year == -1) {\r
-                               if ((style & DateTimeStyles.NoCurrentDateDefault) != 0)\r
-                                       year = 1;\r
-                               else\r
-                                       year = Today.Year;\r
-                       }\r
-\r
-                       if (ampm == 1)\r
-                               hour = hour + 12;\r
-\r
-                       result = new DateTime (year, month, day, hour, minute, second, millisecond);\r
-\r
-                       if ((dayofweek != -1) && (dayofweek != (int) result.DayOfWeek))\r
-                               throw new FormatException (Locale.GetText ("String was not recognized as valid DateTime because the day of week was incorrect."));\r
-\r
-                       // If no timezone was specified, default to the local timezone.\r
-                       TimeSpan utcoffset;\r
-                       if (useutc)\r
-                               utcoffset = new TimeSpan (0, 0, 0);\r
-                       else if (tzsign == -1) {\r
-                               TimeZone tz = TimeZone.CurrentTimeZone;\r
-                               utcoffset = tz.GetUtcOffset (result);\r
-                       } else {\r
-                               if ((style & DateTimeStyles.AdjustToUniversal) != 0)\r
-                                       use_localtime = false;\r
-\r
-                               if (tzoffmin == -1)\r
-                                       tzoffmin = 0;\r
-                               if (tzoffset == -1)\r
-                                       tzoffset = 0;\r
-                               if (tzsign == 1)\r
-                                       tzoffset = -tzoffset;\r
-\r
-                               utcoffset = new TimeSpan (tzoffset, tzoffmin, 0);\r
-                       }\r
-\r
-                       long newticks = (result.ticks - utcoffset).Ticks;\r
-\r
-                       result = new DateTime (use_localtime, newticks);\r
-\r
-                       return true;\r
-               }\r
-\r
-\r
-               public static DateTime ParseExact (string s, string format,\r
-                                                  IFormatProvider fp, DateTimeStyles style)\r
-               {\r
-                       string[] formats;\r
-\r
-                       formats = new string [1];\r
-                       formats[0] = format;\r
-\r
-                       return ParseExact (s, formats, fp, style);\r
-               }\r
-\r
-               public static DateTime ParseExact (string s, string[] formats,\r
-                                                  IFormatProvider fp,\r
-                                                  DateTimeStyles style)\r
-               {\r
-                       DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (fp);\r
-\r
-                       if (s == null)\r
-                               throw new ArgumentNullException (Locale.GetText ("s is null"));\r
-                       if (formats.Length == 0)\r
-                               throw new ArgumentNullException (Locale.GetText ("format is null"));\r
-\r
-                       int i;\r
-                       for (i = 0; i < formats.Length; i++)\r
-                       {\r
-                               DateTime result;\r
-\r
-                               if (_DoParse (s, formats[i], true, out result, dfi, style))\r
-                                       return result;\r
-                       }\r
-\r
-                       throw new FormatException ();\r
-               }\r
-               \r
-               public TimeSpan Subtract(DateTime dt)\r
-               {   \r
-                       return new TimeSpan(ticks.Ticks) - dt.ticks;\r
-               }\r
-\r
-               public DateTime Subtract(TimeSpan ts)\r
-               {\r
-                       TimeSpan newticks;\r
-\r
-                       newticks = (new TimeSpan (ticks.Ticks)) - ts;\r
-                       return new DateTime(true,newticks);\r
-               }\r
-\r
-               public long ToFileTime()\r
-               {\r
-                       if(ticks.Ticks < w32file_epoch) {\r
-                               throw new ArgumentOutOfRangeException("file time is not valid");\r
-                       }\r
-                       \r
-                       return(ticks.Ticks - w32file_epoch);\r
-               }\r
-\r
-               public string ToLongDateString()\r
-               {\r
-                       return ToString ("D");\r
-               }\r
-\r
-               public string ToLongTimeString()\r
-               {\r
-                       return ToString ("T");\r
-               }\r
-\r
-               [MonoTODO]\r
-               public double ToOADate()\r
-               {\r
-                       // TODO implement me \r
-                       return 0;\r
-               }\r
-\r
-               public string ToShortDateString()\r
-               {\r
-                       return ToString ("d");\r
-               }\r
-\r
-               public string ToShortTimeString()\r
-               {\r
-                       return ToString ("t");\r
-               }\r
-               \r
-               public override string ToString ()\r
-               {\r
-                       return ToString ("G", null);\r
-               }\r
-\r
-               public string ToString (IFormatProvider fp)\r
-               {\r
-                       return ToString (null, fp);\r
-               }\r
-\r
-               public string ToString (string format)\r
-               {\r
-                       return ToString (format, null);\r
-               }\r
-\r
-               internal static string _GetStandardPattern (char format, DateTimeFormatInfo dfi, out bool useutc)\r
-               {\r
-                       String pattern;\r
-\r
-                       useutc = false;\r
-\r
-                       switch (format)\r
-                       {\r
-                       case 'd':\r
-                               pattern = dfi.ShortDatePattern;\r
-                               break;\r
-                       case 'D':\r
-                               pattern = dfi.LongDatePattern;\r
-                               break;\r
-                       case 'f':\r
-                               pattern = dfi.LongDatePattern + " " + dfi.ShortTimePattern;\r
-                               break;\r
-                       case 'F':\r
-                               pattern = dfi.FullDateTimePattern;\r
-                               break;\r
-                       case 'g':\r
-                               pattern = dfi.ShortDatePattern + " " + dfi.ShortTimePattern;\r
-                               break;\r
-                       case 'G':\r
-                               pattern = dfi.ShortDatePattern + " " + dfi.LongTimePattern;\r
-                               break;\r
-                       case 'm':\r
-                       case 'M':\r
-                               pattern = dfi.MonthDayPattern;\r
-                               break;\r
-                       case 'r':\r
-                       case 'R':\r
-                               pattern = dfi.RFC1123Pattern;\r
-                               // commented by LP 09/jun/2002, rfc 1123 pattern is always in GMT\r
-                               // useutc= true;\r
-                               break;\r
-                       case 's':\r
-                               pattern = dfi.SortableDateTimePattern;\r
-                               break;\r
-                       case 't':\r
-                               pattern = dfi.ShortTimePattern;\r
-                               break;\r
-                       case 'T':\r
-                               pattern = dfi.LongTimePattern;\r
-                               break;\r
-                       case 'u':\r
-                               pattern = dfi.UniversalSortableDateTimePattern;\r
-                               useutc = true;\r
-                               break;\r
-                       case 'U':\r
-                               pattern = dfi.LongDatePattern + " " + dfi.LongTimePattern;\r
-                               useutc = true;\r
-                               break;\r
-                       case 'y':\r
-                       case 'Y':\r
-                               pattern = dfi.YearMonthPattern;\r
-                               break;\r
-                       default:\r
-                               pattern = null;\r
-                               break;\r
-                       }\r
-\r
-                       return pattern;\r
-               }\r
-\r
-               internal string _ToString (string format, DateTimeFormatInfo dfi)\r
-               {\r
-                       String str = null, result = null;\r
-                       char[] chars = format.ToCharArray ();\r
-                       int len = format.Length, pos = 0, num = 0;\r
-\r
-                       TimeZone tz = TimeZone.CurrentTimeZone;\r
-                       TimeSpan utcoffset = tz.GetUtcOffset (this);\r
-\r
-                       while (pos < len)\r
-                       {\r
-                               if (chars[pos] == '\'') {\r
-                                       num = 1;\r
-                                       while (pos+num <= len) {\r
-                                               if (chars[pos+num] == '\'')\r
-                                                       break;\r
-\r
-                                               result += chars[pos+num];\r
-                                               num++;\r
-                                       }\r
-                                       if (pos+num > len)\r
-                                               throw new FormatException (Locale.GetText ("The specified format is invalid"));\r
-\r
-                                       pos += num+1;\r
-                                       num = 0;\r
-                                       continue;\r
-                               } else if (chars[pos] == '\\') {\r
-                                       if (pos+1 >= len)\r
-                                               throw new FormatException (Locale.GetText ("The specified format is invalid"));\r
-\r
-                                       result += chars[pos+1];\r
-                                       pos += 2;\r
-                                       continue;\r
-                               } else if (chars[pos] == '%') {\r
-                                       pos++;\r
-                                       continue;\r
-                               }\r
-\r
-                               if ((pos+num+1 < len) && (chars[pos+num+1] == chars[pos+num])) {\r
-                                       num++;\r
-                                       continue;\r
-                               }\r
-\r
-                               switch (chars[pos])\r
-                               {\r
-                               case 'd':\r
-                                       if (num == 0)\r
-                                               str = Day.ToString ("d");\r
-                                       else if (num == 1)\r
-                                               str = Day.ToString ("d02");\r
-                                       else if (num == 2)\r
-                                               str = dfi.GetAbbreviatedDayName (DayOfWeek);\r
-                                       else {\r
-                                               str = dfi.GetDayName (DayOfWeek);\r
-                                               num = 3;\r
-                                       }\r
-                                       break;\r
-                               case 'M':\r
-                                       if (num == 0)\r
-                                               str = Month.ToString ("d");\r
-                                       else if (num == 1)\r
-                                               str = Month.ToString ("d02");\r
-                                       else if (num == 2)\r
-                                               str = dfi.GetAbbreviatedMonthName (Month);\r
-                                       else {\r
-                                               str = dfi.GetMonthName (Month);\r
-                                               num = 3;\r
-                                       }\r
-                                       break;\r
-                               case 'y':\r
-                                       if (num == 0) {\r
-                                               int shortyear = Year % 100;\r
-                                               str = shortyear.ToString ("d");\r
-                                       } else if (num == 1) {\r
-                                               int shortyear = Year % 100;\r
-                                               str = shortyear.ToString ("d02");\r
-                                       } else {\r
-                                               str = Year.ToString ("d");\r
-                                               num = 3;\r
-                                       }\r
-                                       break;\r
-                               case 'g':\r
-                                       // FIXME\r
-                                       break;\r
-                               case 'f':\r
-                                       num = Math.Min (num, 6);\r
-\r
-                                       long ms = (long) Millisecond;\r
-                                       long exp = 10;\r
-                                       for (int i = 0; i < num; i++)\r
-                                               exp = exp * 10;\r
-                                       long maxexp = TimeSpan.TicksPerMillisecond;\r
-\r
-                                       exp = Math.Min (exp, maxexp);\r
-                                       ms = ms * exp / maxexp;\r
-\r
-                                       String prec = (num+1).ToString ("d02");\r
-                                       str = ms.ToString (String.Concat ("d", prec));\r
-\r
-                                       break;\r
-                               case 'h':\r
-                                       if (num == 0) {\r
-                                               int shorthour = Hour % 12;\r
-                                               str = shorthour.ToString ("d");\r
-                                       } else {\r
-                                               int shorthour = Hour % 12;\r
-                                               str = shorthour.ToString ("d02");\r
-                                               num = 1;\r
-                                       }\r
-                                       break;\r
-                               case 'H':\r
-                                       if (num == 0)\r
-                                               str = Hour.ToString ("d");\r
-                                       else {\r
-                                               str = Hour.ToString ("d02");\r
-                                               num = 1;\r
-                                       }\r
-                                       break;\r
-                               case 'm':\r
-                                       if (num == 0)\r
-                                               str = Minute.ToString ("d");\r
-                                       else {\r
-                                               str = Minute.ToString ("d02");\r
-                                               num = 1;\r
-                                       }\r
-                                       break;\r
-                               case 's':\r
-                                       if (num == 0)\r
-                                               str = Second.ToString ("d");\r
-                                       else {\r
-                                               str = Second.ToString ("d02");\r
-                                               num = 1;\r
-                                       }\r
-                                       break;\r
-                               case 't':\r
-                                       if (Hour < 12)\r
-                                               str = dfi.AMDesignator;\r
-                                       else\r
-                                               str = dfi.PMDesignator;\r
-\r
-                                       if (num == 0)\r
-                                               str = str.Substring (0,1);\r
-                                       else\r
-                                               num = 1;\r
-                                       break;\r
-                               case 'z':\r
-                                       if (num == 0) {\r
-                                               int offset = utcoffset.Hours;\r
-                                               str = offset.ToString ("d");\r
-                                               if (offset > 0)\r
-                                                       str = String.Concat ("+", str);\r
-                                       } else if (num == 1) {\r
-                                               int offset = utcoffset.Hours;\r
-                                               str = offset.ToString ("d02");\r
-                                               if (offset > 0)\r
-                                                       str = String.Concat ("+", str);\r
-                                       } else if (num == 2) {\r
-                                               int offhour = utcoffset.Hours;\r
-                                               int offminute = utcoffset.Minutes;\r
-                                               str = offhour.ToString ("d02");\r
-                                               str = String.Concat (str, dfi.TimeSeparator);\r
-                                               str = String.Concat (str, offminute.ToString ("d02"));\r
-                                               if (offhour > 0)\r
-                                                       str = String.Concat ("+", str);\r
-                                               num = 2;\r
-                                       }\r
-                                       break;\r
-                               case ':':\r
-                                       str = dfi.TimeSeparator;\r
-                                       num = 0;\r
-                                       break;\r
-                               case '/':\r
-                                       str = dfi.DateSeparator;\r
-                                       num = 0;\r
-                                       break;\r
-                               default:\r
-                                       str = String.Concat (chars [pos]);\r
-                                       num = 0;\r
-                                       break;\r
-                               }\r
-\r
-                               result = String.Concat (result, str);\r
-                                               \r
-                               pos += num + 1;\r
-                               num = 0;\r
-                       }\r
-\r
-                       return result;\r
-               }\r
-\r
-               public string ToString (string format, IFormatProvider fp)\r
-               {\r
-                       DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance(fp);\r
-\r
-                       if (format == null)\r
-                               format = dfi.FullDateTimePattern;\r
-\r
-                       bool useutc = false;\r
-\r
-                       if (format.Length == 1) {\r
-                               char fchar = (format.ToCharArray ())[0];\r
-                               format = _GetStandardPattern (fchar, dfi, out useutc);\r
-                       }\r
-\r
-                       if (useutc)\r
-                               return this.ToUniversalTime ()._ToString (format, dfi);\r
-                       else\r
-                               return this._ToString (format, dfi);\r
-               }\r
-\r
-               public DateTime ToLocalTime()\r
-               {\r
-                       TimeZone tz = TimeZone.CurrentTimeZone;\r
-\r
-                       TimeSpan offset = tz.GetUtcOffset (this);\r
-\r
-                       return new DateTime (true, ticks + offset);\r
-               }\r
-\r
-               public DateTime ToUniversalTime()\r
-               {\r
-                       TimeZone tz = TimeZone.CurrentTimeZone;\r
-\r
-                       TimeSpan offset = tz.GetUtcOffset (this);\r
-\r
-                       return new DateTime (true, ticks - offset);\r
-               }\r
-\r
-               /*  OPERATORS */\r
-\r
-               public static DateTime operator +(DateTime d, TimeSpan t)\r
-               {\r
-                       return new DateTime (true, d.ticks + t);\r
-               }\r
-\r
-               public static bool operator ==(DateTime d1, DateTime d2)\r
-               {\r
-                       return (d1.ticks == d2.ticks);\r
-               }\r
-\r
-               public static bool operator >(DateTime t1,DateTime t2)\r
-               {\r
-                       return (t1.ticks > t2.ticks);\r
-               }\r
-\r
-               public static bool operator >=(DateTime t1,DateTime t2)\r
-               {\r
-                       return (t1.ticks >= t2.ticks);\r
-               }\r
-\r
-               public static bool operator !=(DateTime d1, DateTime d2)\r
-               {\r
-                       return (d1.ticks != d2.ticks);\r
-               }\r
-\r
-               public static bool operator <(DateTime t1,      DateTime t2)\r
-               {\r
-                       return (t1.ticks < t2.ticks );\r
-               }\r
-\r
-               public static bool operator <=(DateTime t1,DateTime t2)\r
-               {\r
-                       return (t1.ticks <= t2.ticks);\r
-               }\r
-\r
-               public static TimeSpan operator -(DateTime d1,DateTime d2)\r
-               {\r
-                       return new TimeSpan((d1.ticks - d2.ticks).Ticks);\r
-               }\r
-\r
-               public static DateTime operator -(DateTime d,TimeSpan t)\r
-               {\r
-                       return new DateTime (true, d.ticks - t);\r
-               }\r
-\r
-               bool IConvertible.ToBoolean(IFormatProvider provider)\r
-               {\r
-                       throw new InvalidCastException();\r
-               }\r
-               \r
-               byte IConvertible.ToByte(IFormatProvider provider)\r
-               {\r
-                       throw new InvalidCastException();\r
-               }\r
-\r
-               char IConvertible.ToChar(IFormatProvider provider)\r
-               {\r
-                       throw new InvalidCastException();\r
-               }\r
-\r
-               // TODO Implement me\r
-               [MonoTODO]\r
-               public System.DateTime ToDateTime(IFormatProvider provider)\r
-               {\r
-                       return new System.DateTime(true,this.ticks);\r
-               } \r
-               \r
-               decimal IConvertible.ToDecimal(IFormatProvider provider)\r
-               {\r
-                        throw new InvalidCastException();\r
-               }\r
-\r
-               double IConvertible.ToDouble(IFormatProvider provider)\r
-               {\r
-                       throw new InvalidCastException();\r
-               }\r
-\r
-               Int16 IConvertible.ToInt16(IFormatProvider provider)\r
-               {\r
-                       throw new InvalidCastException();\r
-               }\r
-\r
-               Int32 IConvertible.ToInt32(IFormatProvider provider)\r
-               {\r
-                       throw new InvalidCastException();\r
-               }\r
-\r
-               Int64 IConvertible.ToInt64(IFormatProvider provider)\r
-               {\r
-                       throw new InvalidCastException();\r
-               }\r
-\r
-               [CLSCompliant(false)]\r
-               SByte IConvertible.ToSByte(IFormatProvider provider)\r
-               {\r
-                       throw new InvalidCastException();\r
-               }\r
-\r
-               Single IConvertible.ToSingle(IFormatProvider provider)\r
-               {\r
-                       throw new InvalidCastException();\r
-               }\r
-\r
-               object IConvertible.ToType(Type conversionType,IFormatProvider provider)\r
-               {\r
-                       throw new InvalidCastException();\r
-               }\r
-\r
-               UInt16 IConvertible.ToUInt16(IFormatProvider provider)\r
-               {\r
-                       throw new InvalidCastException();\r
-               }\r
-               \r
-               [CLSCompliant(false)]\r
-               UInt32 IConvertible.ToUInt32(IFormatProvider provider)\r
-               {\r
-                       throw new InvalidCastException();\r
-               }\r
-\r
-               [CLSCompliant(false)]\r
-               UInt64 IConvertible.ToUInt64(IFormatProvider provider)\r
-               {\r
-                       throw new InvalidCastException();\r
-               }\r
-       }\r
-}\r
-\r
-namespace System\r
-{\r
-       public enum DayOfWeek\r
-       {\r
-               Sunday,\r
-               Monday,\r
-               Tuesday,\r
-               Wednesday,\r
-               Thursday,\r
-               Friday,\r
-               Saturday\r
-       }\r
-}\r
+//
+// System.DateTime.cs
+//
+// author:
+//   Marcel Narings (marcel@narings.nl)
+//   Martin Baulig (martin@gnome.org)
+//   Atsushi Enomoto (atsushi@ximian.com)
+//
+//   (C) 2001 Marcel Narings
+
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace System
+{
+       /// <summary>
+       /// The DateTime structure represents dates and time ranging from
+       /// 1-1-0001 12:00:00 AM to 31-12-9999 23:59:00 Common Era.
+       /// </summary>
+       /// 
+       [Serializable]
+       [StructLayout (LayoutKind.Auto)]
+       public struct DateTime : IFormattable, IConvertible,
+#if NET_2_0
+               IComparable, IComparable<DateTime>
+#else
+               IComparable
+#endif
+       {
+               private TimeSpan ticks;
+
+               private const int dp400 = 146097;
+               private const int dp100 = 36524;
+               private const int dp4 = 1461;
+
+               // w32 file time starts counting from 1/1/1601 00:00 GMT
+               // which is the constant ticks from the .NET epoch
+               private const long w32file_epoch = 504911232000000000L;
+
+               //private const long MAX_VALUE_TICKS = 3155378975400000000L;
+               // -- Microsoft .NET has this value.
+               private const long MAX_VALUE_TICKS = 3155378975999999999L;
+
+               //
+               // The UnixEpoch, it begins on Jan 1, 1970 at 0:0:0, expressed
+               // in Ticks
+               //
+               internal const long UnixEpoch = 621355968000000000L;
+
+               // for OLE Automation dates
+               private const long ticks18991230 = 599264352000000000L;
+               private const double OAMinValue = -657435.0d;
+               private const double OAMaxValue = 2958466.0d;
+
+               public static readonly DateTime MaxValue = new DateTime (false, MAX_VALUE_TICKS);
+               public static readonly DateTime MinValue = new DateTime (false, 0);
+
+               private static readonly string[] commonFormats = {
+                       // For compatibility with MS's CLR, this format (which
+                       // doesn't have a one-letter equivalent) is parsed
+                       // too. It's important because it's used in XML
+                       // serialization.
+
+                       // Note that those format should be tried only for
+                       // invalid patterns; 
+
+                       // FIXME: SOME OF those patterns looks tried against 
+                       // the current culture, since some patterns fail in 
+                       // some culture.
+
+                       "yyyy-MM-dd",
+                       "yyyy-MM-ddTHH:mm:sszzz",
+                       "yyyy-MM-ddTHH:mm:ss.fffffff",
+                       "yyyy-MM-ddTHH:mm:ss.fffffffzzz",
+                       // UTC / allow any separator
+                       "yyyy/MM/ddTHH:mm:ssZ",
+                       "yyyy/M/dZ",
+                       // bug #58938
+                       "yyyy/M/d HH:mm:ss",
+                       // bug #47720
+                       "yyyy/MM/dd HH:mm:ss 'GMT'",
+                       // Close to RFC1123, but without 'GMT'
+                       "ddd, d MMM yyyy HH:mm:ss",
+                       // use UTC ('Z'; not literal "'Z'")
+                       // FIXME: 1078(af-ZA) and 1079(ka-GE) reject it
+                       "yyyy/MM/dd HH':'mm':'ssZ", 
+
+                       // DayOfTheWeek, dd full_month_name yyyy
+                       // FIXME: 1054(th-TH) rejects it
+                       "dddd, dd MMMM yyyy",
+                       // DayOfTheWeek, dd yyyy. This works for every locales.
+                       "MMMM dd, yyyy",
+#if NET_1_1
+                       // X509Certificate pattern is accepted by Parse() *in every culture*
+                       "yyyyMMddHHmmssZ",
+#endif
+                       // In Parse() the 'r' equivalent pattern is first parsed as universal time
+                       "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'",
+/*
+                       // Full date and time
+                       "F", "G", "r", "s", "u", "U",
+                       // Full date and time, but no seconds
+                       "f", "g",
+                       // Only date
+                       "d", "D",
+                       // Only time
+                       "T", "t",
+                       // Only date, but no year
+                       "m",
+                       // Only date, but no day
+                       "y" 
+*/
+               };
+
+               private enum Which 
+               {
+                       Day,
+                       DayYear,
+                       Month,
+                       Year
+               };
+       
+               private static readonly int[] daysmonth = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };        
+               private static readonly int[] daysmonthleap = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };    
+
+               private static int AbsoluteDays (int year, int month, int day)
+               {
+                       int[] days;
+                       int temp = 0, m=1 ;
+
+
+
+
+               
+                       days = (IsLeapYear(year) ? daysmonthleap  : daysmonth);
+                       
+                       while (m < month)
+                               temp += days[m++];
+                       return ((day-1) + temp + (365* (year-1)) + ((year-1)/4) - ((year-1)/100) + ((year-1)/400));
+               }
+
+               private int FromTicks(Which what)
+               {
+                       int num400, num100, num4, numyears; 
+                       int M =1;
+
+                       int[] days = daysmonth;
+                       int totaldays = this.ticks.Days;
+
+                       num400 = (totaldays / dp400);
+                       totaldays -=  num400 * dp400;
+               
+                       num100 = (totaldays / dp100);
+                       if (num100 == 4)   // leap
+                               num100 = 3;
+                       totaldays -= (num100 * dp100);
+
+                       num4 = totaldays / dp4;
+                       totaldays -= (num4 * dp4);
+
+                       numyears = totaldays / 365 ;
+
+                       if (numyears == 4)  //leap
+                               numyears =3 ;
+                       if (what == Which.Year )
+                               return num400*400 + num100*100 + num4*4 + numyears + 1;
+
+                       totaldays -= (numyears * 365) ;
+                       if (what == Which.DayYear )
+                               return totaldays + 1;
+                       
+                       if  ((numyears==3) && ((num100 == 3) || !(num4 == 24)) ) //31 dec leapyear
+                               days = daysmonthleap;
+                               
+                       while (totaldays >= days[M])
+                               totaldays -= days[M++];
+
+                       if (what == Which.Month )
+                               return M;
+
+                       return totaldays +1; 
+               }
+
+
+               // Constructors
+               
+               /// <summary>
+               /// Constructs a DateTime for specified ticks
+               /// </summary>
+               /// 
+               public DateTime (long newticks)
+                       // `local' must default to false here to avoid
+                       // a recursion loop.
+                       : this (false, newticks) {}
+
+               internal DateTime (bool local, long newticks)
+               {
+                       ticks = new TimeSpan (newticks);
+                       if (local) {
+                               TimeZone tz = TimeZone.CurrentTimeZone;
+
+                               TimeSpan utcoffset = tz.GetUtcOffset (this);
+
+                               ticks = ticks + utcoffset;
+                       }
+                       if (ticks.Ticks < MinValue.Ticks || ticks.Ticks > MaxValue.Ticks)
+                           throw new ArgumentOutOfRangeException ();
+               }
+
+               public DateTime (int year, int month, int day)
+                       : this (year, month, day,0,0,0,0) {}
+
+               public DateTime (int year, int month, int day, int hour, int minute, int second)
+                       : this (year, month, day, hour, minute, second, 0)      {}
+
+               public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond)
+                       {
+                       if ( year < 1 || year > 9999 || 
+                               month < 1 || month >12  ||
+                               day < 1 || day > DaysInMonth(year, month) ||
+                               hour < 0 || hour > 23 ||
+                               minute < 0 || minute > 59 ||
+                               second < 0 || second > 59 ||
+                               millisecond < 0 || millisecond > 999)
+                               throw new ArgumentOutOfRangeException ("Parameters describe an " +
+                                                                       "unrepresentable DateTime.");
+
+                       ticks = new TimeSpan (AbsoluteDays(year,month,day), hour, minute, second, millisecond);
+               }
+
+               public DateTime (int year, int month, int day, Calendar calendar)
+                       : this (year, month, day, 0, 0, 0, 0, calendar) {}
+
+               
+               public DateTime (int year, int month, int day, int hour, int minute, int second, Calendar calendar)
+                       : this (year, month, day, hour, minute, second, 0, calendar)    {}
+
+
+               public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar)
+                       : this (year, month, day, hour, minute, second, millisecond) 
+               {
+                       if (calendar == null)
+                               throw new ArgumentNullException();
+               }
+
+               internal DateTime (bool check, TimeSpan value)
+               {
+                       if (check && (value.Ticks < MinValue.Ticks || value.Ticks > MaxValue.Ticks))
+                           throw new ArgumentOutOfRangeException ();
+
+                       ticks = value;
+               }
+
+               /* Properties  */
+
+               public DateTime Date 
+               {
+                       get     
+                       { 
+                               return new DateTime (Year, Month, Day);
+                       }
+               }
+        
+               public int Month 
+               {
+                       get     
+                       { 
+                               return FromTicks(Which.Month); 
+                       }
+               }
+
+              
+               public int Day
+               {
+                       get 
+                       { 
+                               return FromTicks(Which.Day); 
+                       }
+               }
+
+               public DayOfWeek DayOfWeek 
+               {
+                       get 
+                       { 
+                               return ( (DayOfWeek) ((ticks.Days+1) % 7) ); 
+                       }
+               }
+
+               public int DayOfYear 
+               {
+                       get 
+                       { 
+                               return FromTicks(Which.DayYear); 
+                       }
+               }
+
+               public TimeSpan TimeOfDay 
+               {
+                       get     
+                       { 
+                               return new TimeSpan(ticks.Ticks % TimeSpan.TicksPerDay );
+                       }
+                       
+               }
+
+               public int Hour 
+               {
+                       get 
+                       { 
+                               return ticks.Hours;
+                       }
+               }
+
+               public int Minute 
+               {
+                       get 
+                       { 
+                               return ticks.Minutes;
+                       }
+               }
+
+               public int Second 
+               {
+                       get     
+                       { 
+                               return ticks.Seconds;
+                       }
+               }
+
+               public int Millisecond 
+               {
+                       get 
+                       { 
+                               return ticks.Milliseconds;
+                       }
+               }
+               
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               internal static extern long GetNow ();
+
+               public static DateTime Now 
+               {
+                       get     
+                       {
+                               return new DateTime (true, GetNow ());
+                       }
+               }
+
+               public long Ticks
+               { 
+                       get     
+                       { 
+                               return ticks.Ticks;
+                       }
+               }
+       
+               public static DateTime Today 
+               {
+                       get {
+                               DateTime now = Now;
+                               return new DateTime (now.Year, now.Month, now.Day);
+                       }
+               }
+
+               public static DateTime UtcNow 
+               {
+                       get {
+                               return new DateTime (GetNow ());
+                       }
+               }
+
+               public int Year 
+               {
+                       get 
+                       { 
+                               return FromTicks(Which.Year); 
+                       }
+               }
+
+               /* methods */
+
+               public DateTime Add (TimeSpan ts)
+               {
+                       return AddTicks (ts.Ticks);
+               }
+
+               public DateTime AddDays (double days)
+               {
+                       return AddMilliseconds (Math.Round (days * 86400000));
+               }
+               
+               public DateTime AddTicks (long t)
+               {
+                       if ((t + ticks.Ticks) > MAX_VALUE_TICKS || (t + ticks.Ticks) < 0) {
+                               throw new ArgumentOutOfRangeException();
+                       }
+                       return new DateTime (t + ticks.Ticks);
+               }
+
+               public DateTime AddHours (double hours)
+               {
+                       return AddMilliseconds (hours * 3600000);
+               }
+
+               public DateTime AddMilliseconds (double ms)
+               {
+                       if ((ms * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
+                                       (ms * TimeSpan.TicksPerMillisecond) < long.MinValue) {
+                               throw new ArgumentOutOfRangeException();
+                       }
+                       long msticks = (long) (ms * TimeSpan.TicksPerMillisecond);
+
+                       return AddTicks (msticks);
+               }
+
+               // required to match MS implementation for OADate (OLE Automation)
+               private DateTime AddRoundedMilliseconds (double ms)
+               {
+                       if ((ms * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
+                               (ms * TimeSpan.TicksPerMillisecond) < long.MinValue) {
+                               throw new ArgumentOutOfRangeException ();
+                       }
+                       long msticks = (long) (ms += ms > 0 ? 0.5 : -0.5) * TimeSpan.TicksPerMillisecond;
+
+                       return AddTicks (msticks);
+               }
+
+               public DateTime AddMinutes (double minutes)
+               {
+                       return AddMilliseconds (minutes * 60000);
+               }
+               
+               public DateTime AddMonths (int months)
+               {
+                       int day, month, year,  maxday ;
+                       DateTime temp ;
+
+                       day = this.Day;
+                       month = this.Month + (months % 12);
+                       year = this.Year + months/12 ;
+                       
+                       if (month < 1)
+                       {
+                               month = 12 + month ;
+                               year -- ;
+                       }
+                       else if (month>12) 
+                       {
+                               month = month -12;
+                               year ++;
+                       }
+                       maxday = DaysInMonth(year, month);
+                       if (day > maxday)
+                               day = maxday;
+
+                       temp = new DateTime (year, month, day);
+                       return  temp.Add (this.TimeOfDay);
+               }
+
+               public DateTime AddSeconds (double seconds)
+               {
+                       return AddMilliseconds (seconds*1000);
+               }
+
+               public DateTime AddYears (int years )
+               {
+                       return AddMonths(years * 12);
+               }
+
+               public static int Compare (DateTime t1, DateTime t2)
+               {
+                       if (t1.ticks < t2.ticks) 
+                               return -1;
+                       else if (t1.ticks > t2.ticks) 
+                               return 1;
+                       else
+                               return 0;
+               }
+
+               public int CompareTo (object v)
+               {
+                       if ( v == null)
+                               return 1;
+
+                       if (!(v is System.DateTime))
+                               throw new ArgumentException (Locale.GetText (
+                                       "Value is not a System.DateTime"));
+
+                       return Compare (this, (DateTime) v);
+               }
+
+#if NET_2_0
+               public int CompareTo (DateTime value)
+               {
+                       return Compare (this, value);
+               }
+
+               public bool Equals (DateTime value)
+               {
+                       return value.ticks == ticks;
+               }
+#endif
+
+               public static int DaysInMonth (int year, int month)
+               {
+                       int[] days ;
+
+                       if (month < 1 || month >12)
+                               throw new ArgumentOutOfRangeException ();
+
+                       days = (IsLeapYear(year) ? daysmonthleap  : daysmonth);
+                       return days[month];                     
+               }
+               
+               public override bool Equals (object o)
+               {
+                       if (!(o is System.DateTime))
+                               return false;
+
+                       return ((DateTime) o).ticks == ticks;
+               }
+
+               public static bool Equals (DateTime t1, DateTime t2 )
+               {
+                       return (t1.ticks == t2.ticks );
+               }
+
+               public static DateTime FromFileTime (long fileTime) 
+               {
+                       if (fileTime < 0)
+                               throw new ArgumentOutOfRangeException ("fileTime", "< 0");
+
+                       return new DateTime (true, w32file_epoch + fileTime);
+               }
+
+#if NET_1_1
+               public static DateTime FromFileTimeUtc (long fileTime) 
+               {
+                       if (fileTime < 0)
+                               throw new ArgumentOutOfRangeException ("fileTime", "< 0");
+
+                       return new DateTime (false, w32file_epoch + fileTime);
+               }
+#endif
+
+               public static DateTime FromOADate (double d)
+               {
+                       // An OLE Automation date is implemented as a floating-point number
+                       // whose value is the number of days from midnight, 30 December 1899.
+
+                       // d must be negative 657435.0 through positive 2958466.0.
+                       if ((d <= OAMinValue) || (d >= OAMaxValue))
+                               throw new ArgumentException ("d", "[-657435,2958466]");
+
+                       DateTime dt = new DateTime (ticks18991230);
+                       if (d < 0.0d) {
+                               Double days = Math.Ceiling (d);
+                               // integer part is the number of days (negative)
+                               dt = dt.AddRoundedMilliseconds (days * 86400000);
+                               // but decimals are the number of hours (in days fractions) and positive
+                               Double hours = (days - d);
+                               dt = dt.AddRoundedMilliseconds (hours * 86400000);
+                       }
+                       else {
+                               dt = dt.AddRoundedMilliseconds (d * 86400000);
+                       }
+
+                       return dt;
+               }
+
+               public string[] GetDateTimeFormats() 
+               {
+                       return GetDateTimeFormats (CultureInfo.CurrentCulture);
+               }
+
+               public string[] GetDateTimeFormats(char format)
+               {
+                       if ("dDgGfFmMrRstTuUyY".IndexOf (format) < 0)
+                               throw new FormatException ("Invalid format character.");
+                       string[] result = new string[1];
+                       result[0] = this.ToString(format.ToString());
+                       return result;
+               }
+               
+               public string[] GetDateTimeFormats(IFormatProvider provider)
+               {
+                       DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
+//                     return GetDateTimeFormats (info.GetAllDateTimePatterns ());
+                       ArrayList al = new ArrayList ();
+                       foreach (char c in "dDgGfFmMrRstTuUyY")
+                               al.AddRange (GetDateTimeFormats (c, info));
+                       return al.ToArray (typeof (string)) as string [];
+               }
+
+               public string[] GetDateTimeFormats(char format,IFormatProvider provider )
+               {
+                       if ("dDgGfFmMrRstTuUyY".IndexOf (format) < 0)
+                               throw new FormatException ("Invalid format character.");
+
+                       // LAMESPEC: There is NO assurance that 'U' ALWAYS
+                       // euqals to 'F', but since we have to iterate all
+                       // the pattern strings, we cannot just use 
+                       // ToString("U", provider) here. I believe that the 
+                       // method's behavior cannot be formalized.
+                       bool adjustutc = false;
+                       switch (format) {
+                       case 'U':
+//                     case 'r':
+//                     case 'R':
+//                     case 'u':
+                               adjustutc = true;
+                               break;
+                       }
+                       DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
+                       return GetDateTimeFormats (adjustutc, info.GetAllDateTimePatterns (format), info);
+               }
+
+               private string [] GetDateTimeFormats (bool adjustutc, string [] patterns, DateTimeFormatInfo dfi)
+               {
+                       string [] results = new string [patterns.Length];
+                       DateTime val = adjustutc ? ToUniversalTime () : this;
+                       for (int i = 0; i < results.Length; i++)
+                               results [i] = val._ToString (patterns [i], dfi);
+                       return results;
+               }
+
+               public override int GetHashCode ()
+               {
+                       return (int) ticks.Ticks;
+               }
+
+               public TypeCode GetTypeCode ()
+               {
+                       return TypeCode.DateTime;
+               }
+
+               public static bool IsLeapYear (int year)
+               {
+                       return  ( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ;
+               }
+
+               public static DateTime Parse (string s)
+               {
+                       return Parse (s, null);
+               }
+
+               public static DateTime Parse (string s, IFormatProvider fp)
+               {
+                       return Parse (s, fp, DateTimeStyles.AllowWhiteSpaces);
+               }
+
+               [MonoTODO ("see the comments inline")]
+               public static DateTime Parse (string s, IFormatProvider fp, DateTimeStyles styles)
+               {
+                       // This method should try only expected patterns. 
+                       // Should not try extra patterns.
+                       // Right now we also try InvariantCulture, but I
+                       // confirmed in some cases this method rejects what
+                       // InvariantCulture supports (can be checked against
+                       // "th-TH" with Gregorian Calendar). So basically it
+                       // should not be done.
+                       // I think it should be CurrentCulture to be tested,
+                       // but right now we don't support all the supported
+                       // patterns for each culture, so try InvariantCulture
+                       // as a quick remedy.
+                       if (s == null)
+                               throw new ArgumentNullException (Locale.GetText ("s is null"));
+                       DateTime result;
+
+                       if (fp == null)
+                               fp = CultureInfo.CurrentCulture;
+                       DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (fp);
+
+                       bool longYear = false;
+                       // Try common formats.
+                       if (ParseExact (s, commonFormats, dfi, styles, out result, false, ref longYear))
+                               return result;
+
+                       // Try common formats, also with invariant culture
+                       if (ParseExact (s, commonFormats, DateTimeFormatInfo.InvariantInfo, styles, out result, false, ref longYear))
+                               return result;
+
+                       // Next, try all the patterns
+                       string [] patterns = new string [] {"d", "D", "g", "G", "f", "F", "m", "M", "r", "R", "s", "t", "T", "u", "U", "y", "Y"};
+
+                       if (ParseExact (s, patterns, dfi, styles, out result, false, ref longYear))
+                               return result;
+
+                       if (longYear) {
+                               throw new ArgumentOutOfRangeException ("year",
+                                       "Valid values are between 1 and 9999 inclusive");
+                       }
+
+                       throw new FormatException ("String was not recognized as a valid DateTime.");
+               }
+
+               public static DateTime ParseExact (string s, string format, IFormatProvider fp)
+               {
+                       return ParseExact (s, format, fp, DateTimeStyles.None);
+               }
+
+               internal static int _ParseNumber (string s, int valuePos,
+                                                 int digits,
+                                                 bool leadingzero,
+                                                 bool sloppy_parsing,
+                                                 bool next_not_digit,
+                                                 out int num_parsed)
+               {
+                       int number = 0, i;
+
+                       if (sloppy_parsing)
+                               leadingzero = false;
+
+                       if (!leadingzero) {
+                               int real_digits = 0;
+                               for (i = valuePos; i < s.Length && i < digits + valuePos; i++) {
+                                       if (!Char.IsDigit (s[i]))
+                                               break;
+
+                                       real_digits++;
+                               }
+
+                               digits = real_digits;
+                       }
+
+                       if (s.Length - valuePos < digits) {
+                               num_parsed = -1;
+                               return 0;
+                       }
+
+                       if (s.Length - valuePos > digits &&
+                           next_not_digit &&
+                           Char.IsDigit (s[digits + valuePos])) {
+                               /* More digits left over */
+                               num_parsed = -1;
+                               return(0);
+                       }
+
+                       for (i = valuePos; i < digits + valuePos; i++) {
+                               char c = s[i];
+                               if (!Char.IsDigit (c)) {
+                                       num_parsed = -1;
+                                       return 0;
+                               }
+
+                               number = number * 10 + (byte) (c - '0');
+                       }
+
+                       num_parsed = digits;
+                       return number;
+               }
+
+               internal static int _ParseEnum (string s, int sPos, string[] values, out int num_parsed)
+               {
+                       int i;
+
+                       for (i = 0; i < values.Length; i++) {
+                               if (s.Length - sPos < values[i].Length)
+                                       continue;
+                               else if (values [i].Length == 0)
+                                       continue;
+                               String tmp = s.Substring (sPos, values[i].Length);
+                               if (String.Compare (tmp, values[i], true) == 0) {
+                                       num_parsed = values[i].Length;
+                                       return i;
+                               }
+                       }
+
+                       num_parsed = -1;
+                       return -1;
+               }
+
+               internal static bool _ParseString (string s, int sPos, int maxlength, string value, out int num_parsed)
+               {
+                       if (maxlength <= 0)
+                               maxlength = value.Length;
+
+                       if (String.Compare (s, sPos, value, 0, maxlength, true, CultureInfo.InvariantCulture) == 0) {
+                               num_parsed = maxlength;
+                               return true;
+                       }
+
+                       num_parsed = -1;
+                       return false;
+               }
+
+               private static bool _DoParse (string s, string format, bool exact,
+                                              out DateTime result,
+                                              DateTimeFormatInfo dfi,
+                                              DateTimeStyles style,
+                                              ref bool longYear)
+               {
+                       bool useutc = false, use_localtime = true;
+                       bool use_invariant = false;
+                       bool sloppy_parsing = false;
+                       int valuePos = 0;
+                       if (format.Length == 1)
+                               format = _GetStandardPattern (format [0], dfi, out useutc, out use_invariant);
+                       else if (!exact && format.IndexOf ("GMT") >= 0)
+                               useutc = true;
+
+                       if ((style & DateTimeStyles.AllowLeadingWhite) != 0) {
+                               format = format.TrimStart (null);
+
+                               s = s.TrimStart (null); // it could be optimized, but will make little good.
+                       }
+
+                       if ((style & DateTimeStyles.AllowTrailingWhite) != 0) {
+                               format = format.TrimEnd (null);
+                               s = s.TrimEnd (null); // it could be optimized, but will make little good.
+                       }
+
+                       if (use_invariant)
+                               dfi = DateTimeFormatInfo.InvariantInfo;
+
+                       if ((style & DateTimeStyles.AllowInnerWhite) != 0)
+                               sloppy_parsing = true;
+
+                       string chars = format;
+                       int len = format.Length, pos = 0, num = 0;
+
+                       int day = -1, dayofweek = -1, month = -1, year = -1;
+                       int hour = -1, minute = -1, second = -1;
+                       double fractionalSeconds = -1;
+                       int ampm = -1;
+                       int tzsign = -1, tzoffset = -1, tzoffmin = -1;
+                       bool next_not_digit;
+
+                       result = new DateTime (0);
+                       while (pos+num < len)
+                       {
+                               if (s.Length == valuePos)
+                                       break;
+
+                               if (chars[pos] == '\'') {
+                                       num = 1;
+                                       while (pos+num < len) {
+                                               if (chars[pos+num] == '\'')
+                                                       break;
+
+                                               if (valuePos == s.Length)
+                                                       return false;
+                                               if (s [valuePos] != chars [pos + num])
+                                                       return false;
+                                               valuePos++;
+
+                                               num++;
+                                       }
+                                       if (pos+num > len)
+                                               return false;
+
+                                       pos += num + 1;
+                                       num = 0;
+                                       continue;
+                               } else if (chars[pos] == '"') {
+                                       num = 1;
+                                       while (pos+num < len) {
+                                               if (chars[pos+num] == '"')
+                                                       break;
+
+                                               if (valuePos == s.Length)
+                                                       return false;
+                                               if (s [valuePos] != chars[pos+num])
+                                                       return false;
+                                               valuePos++;
+
+                                               num++;
+                                       }
+                                       if (pos+num > len)
+                                               return false;
+
+                                       pos += num + 1;
+                                       num = 0;
+                                       continue;
+                               } else if (chars[pos] == '\\') {
+                                       if (pos+1 >= len)
+                                               return false;
+
+                                       if (s [valuePos] != chars [pos + num])
+                                               return false;
+                                       valuePos++;
+                                       if (valuePos == s.Length)
+                                               return false;
+
+                                       pos++;
+                                       continue;
+                               } else if (chars[pos] == '%') {
+                                       pos++;
+                                       continue;
+                               } else if (Char.IsWhiteSpace (s [valuePos])) {
+                                       valuePos++;
+
+                                       if (Char.IsWhiteSpace (chars[pos])) {
+                                               pos++;
+                                               continue;
+                                       }
+
+                                       if (exact && (style & DateTimeStyles.AllowInnerWhite) == 0)
+                                               return false;
+                                       int ws = valuePos;
+                                       while (ws < s.Length) {
+                                               if (Char.IsWhiteSpace (s [ws]))
+                                                       ws++;
+                                               else
+                                                       break;
+                                       }
+                                       valuePos = ws;
+                               }
+
+
+                               if ((pos+num+1 < len) && (chars[pos+num+1] == chars[pos+num])) {
+                                       num++;
+                                       continue;
+                               }
+
+                               int num_parsed = 0;
+
+                               if (pos+num+1 < len) {
+                                       char next_char = chars[pos+num+1];
+                                       
+                                       next_not_digit = !(next_char == 'd' ||
+                                                          next_char == 'M' ||
+                                                          next_char == 'y' ||
+                                                          next_char == 'h' ||
+                                                          next_char == 'H' ||
+                                                          next_char == 'm' ||
+                                                          next_char == 's' ||
+                                                          next_char == 'f' ||
+                                                          next_char == 'z' ||
+                                                          next_char == '"' ||
+                                                          next_char == '\'' ||
+                                                          Char.IsDigit (next_char));
+                               } else {
+                                       next_not_digit = true;
+                               }
+                               
+                               switch (chars[pos])
+                               {
+                               case 'd':
+                                       if (day != -1)
+                                               return false;
+                                       if (num == 0)
+                                               day = _ParseNumber (s, valuePos, 2, false, sloppy_parsing, next_not_digit, out num_parsed);
+                                       else if (num == 1)
+                                               day = _ParseNumber (s, valuePos, 2, true, sloppy_parsing, next_not_digit, out num_parsed);
+                                       else if (num == 2)
+                                               dayofweek = _ParseEnum (s, valuePos, dfi.AbbreviatedDayNames, out num_parsed);
+                                       else
+                                       {
+                                               dayofweek = _ParseEnum (s, valuePos, dfi.DayNames, out num_parsed);
+                                               num = 3;
+                                       }
+                                       break;
+                               case 'M':
+                                       if (month != -1)
+                                               return false;
+                                       if (num == 0)
+                                               month = _ParseNumber (s, valuePos, 2, false, sloppy_parsing, next_not_digit, out num_parsed);
+                                       else if (num == 1)
+                                               month = _ParseNumber (s, valuePos, 2, true, sloppy_parsing, next_not_digit, out num_parsed);
+                                       else if (num == 2)
+                                               month = _ParseEnum (s, valuePos, dfi.AbbreviatedMonthNames , out num_parsed) + 1;
+                                       else
+                                       {
+                                               month = _ParseEnum (s, valuePos, dfi.MonthNames, out num_parsed) + 1;
+                                               num = 3;
+                                       }
+                                       break;
+                               case 'y':
+                                       if (year != -1)
+                                               return false;
+
+                                       if (num == 0) {
+                                               year = _ParseNumber (s, valuePos, 2, false, sloppy_parsing, next_not_digit, out num_parsed);
+                                       } else if (num < 3) {
+                                               year = _ParseNumber (s, valuePos, 2, true, sloppy_parsing, next_not_digit, out num_parsed);
+                                       } else {
+                                               year = _ParseNumber (s, valuePos, 4, false, sloppy_parsing, next_not_digit, out num_parsed);
+                                               if ((year >= 1000) && (num_parsed == 4) && (!longYear) && (s.Length > 4 + valuePos)) {
+                                                       int np = 0;
+                                                       int ly = _ParseNumber (s, valuePos, 5, false, sloppy_parsing, next_not_digit, out np);
+                                                       longYear = (ly > 9999);
+                                               }
+                                               num = 3;
+                                       }
+
+                                       //FIXME: We should do use dfi.Calendat.TwoDigitYearMax
+                                       if (num_parsed <= 2)
+                                               year += (year < 30) ? 2000 : 1900;
+                                       break;
+                               case 'h':
+                                       if (hour != -1)
+                                               return false;
+                                       if (num == 0)
+                                               hour = _ParseNumber (s, valuePos, 2, false, sloppy_parsing, next_not_digit, out num_parsed);
+                                       else
+                                       {
+                                               hour = _ParseNumber (s, valuePos, 2, true, sloppy_parsing, next_not_digit, out num_parsed);
+                                               num = 1;
+                                       }
+
+                                       if (hour > 12)
+                                               return false;
+                                       if (hour == 12)
+                                               hour = 0;
+
+                                       break;
+                               case 'H':
+                                       if ((hour != -1) || (ampm >= 0))
+                                               return false;
+                                       if (num == 0)
+                                               hour = _ParseNumber (s, valuePos, 2, false, sloppy_parsing, next_not_digit, out num_parsed);
+                                       else
+                                       {
+                                               hour = _ParseNumber (s, valuePos, 2, true, sloppy_parsing, next_not_digit, out num_parsed);
+                                               num = 1;
+                                       }
+                                       if (hour >= 24)
+                                               return false;
+
+                                       ampm = -2;
+                                       break;
+                               case 'm':
+                                       if (minute != -1)
+                                               return false;
+                                       if (num == 0)
+                                               minute = _ParseNumber (s, valuePos, 2, false, sloppy_parsing, next_not_digit, out num_parsed);
+                                       else
+                                       {
+                                               minute = _ParseNumber (s, valuePos, 2, true, sloppy_parsing, next_not_digit, out num_parsed);
+                                               num = 1;
+                                       }
+                                       if (minute >= 60)
+                                               return false;
+
+                                       break;
+                               case 's':
+                                       if (second != -1)
+                                               return false;
+                                       if (num == 0)
+                                               second = _ParseNumber (s, valuePos, 2, false, sloppy_parsing, next_not_digit, out num_parsed);
+                                       else
+                                       {
+                                               second = _ParseNumber (s, valuePos, 2, true, sloppy_parsing, next_not_digit, out num_parsed);
+                                               num = 1;
+                                       }
+                                       if (second >= 60)
+                                               return false;
+
+                                       break;
+                               case 'f':
+                                       if (fractionalSeconds != -1)
+                                               return false;
+                                       num = Math.Min (num, 6);
+                                       double decimalNumber = (double) _ParseNumber (s, valuePos, num+1, true, sloppy_parsing, next_not_digit, out num_parsed);
+                                       if (num_parsed == -1)
+                                               return false;
+
+                                       else
+                                               fractionalSeconds = decimalNumber / Math.Pow(10.0, num_parsed);
+                                       break;
+                               case 't':
+                                       if (ampm != -1)
+                                               return false;
+                                       if (num == 0)
+                                       {
+                                               if (_ParseString (s, valuePos, 1, dfi.AMDesignator, out num_parsed))
+                                                       ampm = 0;
+                                               else if (_ParseString (s, valuePos, 1, dfi.PMDesignator, out num_parsed))
+                                                       ampm = 1;
+                                               else
+                                                       return false;
+                                       }
+                                       else
+                                       {
+                                               if (_ParseString (s, valuePos, 0, dfi.AMDesignator, out num_parsed))
+                                                       ampm = 0;
+                                               else if (_ParseString (s, valuePos, 0, dfi.PMDesignator, out num_parsed))
+                                                       ampm = 1;
+                                               else
+                                                       return false;
+                                               num = 1;
+                                       }
+                                       break;
+                               case 'z':
+                                       if (tzsign != -1)
+                                               return false;
+                                       if (s [valuePos] == '+')
+                                               tzsign = 0;
+                                       else if (s [valuePos] == '-')
+                                               tzsign = 1;
+                                       else
+                                               return false;
+                                       valuePos++;
+                                       if (num == 0)
+                                               tzoffset = _ParseNumber (s, valuePos, 2, false, sloppy_parsing, next_not_digit, out num_parsed);
+                                       else if (num == 1)
+                                               tzoffset = _ParseNumber (s, valuePos, 2, true, sloppy_parsing, false, out num_parsed);
+                                       else
+                                       {
+                                               tzoffset = _ParseNumber (s, valuePos, 2, true, sloppy_parsing, next_not_digit, out num_parsed);
+                                               if (num_parsed < 0)
+                                                       return false;
+                                               valuePos += num_parsed;
+                                               if (Char.IsDigit (s [valuePos]))
+                                                       num_parsed = 0;
+                                               else if (!_ParseString (s, valuePos, 0, dfi.TimeSeparator, out num_parsed))
+                                                       return false;
+                                               valuePos += num_parsed;
+                                               tzoffmin = _ParseNumber (s, valuePos, 2, true, sloppy_parsing, false, out num_parsed);
+                                               if (num_parsed < 0)
+                                                       return false;
+                                               num = 2;
+                                       }
+                                       break;
+
+                               // LAMESPEC: This should be part of UTCpattern
+                               // string and thus should not be considered here.
+                               //
+                               // Note that 'Z' is not defined as a pattern
+                               // character. Keep it for X509 certificate
+                               // verification. Also, "Z" != "'Z'" under MS.NET
+                               // ("'Z'" is just literal; handled above)
+                               case 'Z':
+                                       if (s [valuePos] != 'Z')
+                                               return false;
+                                       num = 0;
+                                       num_parsed = 1;
+                                       useutc = true;
+                                       break;
+
+                               case ':':
+                                       if (!_ParseString (s, valuePos, 0, dfi.TimeSeparator, out num_parsed))
+                                               return false;
+                                       break;
+                               case '/':
+                                       /* Accept any character for
+                                        * DateSeparator, except
+                                        * TimeSeparator, a digit or a
+                                        * letter.  Not documented,
+                                        * but seems to be MS
+                                        * behaviour here.  See bug
+                                        * 54047.
+                                        */
+                                       if (exact && s [valuePos] != '/')
+                                               return false;
+
+                                       if (_ParseString (s, valuePos, 0,
+                                                         dfi.TimeSeparator,
+                                                         out num_parsed) ||
+                                           Char.IsDigit (s [valuePos]) ||
+                                           Char.IsLetter (s [valuePos])) {
+                                               return(false);
+                                       }
+
+                                       num = 0;
+                                       if (num_parsed <= 0) {
+                                               num_parsed = 1;
+                                       }
+                                       
+                                       break;
+                               default:
+                                       if (s [valuePos] != chars[pos]) {
+                                               // FIXME: It is not sure, but
+                                               // IsLetter() is introduced 
+                                               // because we have to reject 
+                                               // "2002a02b25" but have to
+                                               // allow "2002$02$25". The same
+                                               // thing applies to '/' case.
+                                               if (exact ||
+                                                       Char.IsDigit (s [valuePos]) ||
+                                                       Char.IsLetter (s [valuePos]))
+                                                       return false;
+                                       }
+                                       num = 0;
+                                       num_parsed = 1;
+                                       break;
+                               }
+
+                               if (num_parsed < 0)
+                                       return false;
+
+                               valuePos += num_parsed;
+
+                               if (!exact) {
+                                       switch (chars [pos]) {
+                                       case 'm':
+                                       case 's':
+                                       case 'f':
+                                       case 'z':
+                                               if (s.Length > valuePos && s [valuePos] == 'Z'
+                                                   && (pos + 1 == chars.Length
+                                                   || chars [pos + 1] != 'Z')) {
+                                                       useutc = true;
+                                                       valuePos++;
+                                               }
+                                               break;
+                                       }
+                               }
+
+                               pos = pos + num + 1;
+                               num = 0;
+                       }
+
+                       if (exact && pos < len)
+                               return false;
+
+                       if (s.Length != valuePos) // extraneous tail.
+                               return false;
+
+                       if (hour == -1)
+                               hour = 0;
+                       if (minute == -1)
+                               minute = 0;
+
+                       if (second == -1)
+                               second = 0;
+                       if (fractionalSeconds == -1)
+                               fractionalSeconds = 0;
+
+                       // If no date was given
+                       if ((day == -1) && (month == -1) && (year == -1)) {
+                               if ((style & DateTimeStyles.NoCurrentDateDefault) != 0) {
+                                       day = 1;
+                                       month = 1;
+                                       year = 1;
+                               } else {
+                                       day = Today.Day;
+                                       month = Today.Month;
+                                       year = Today.Year;
+                               }
+                       }
+
+
+                       if (day == -1)
+                               day = 1;
+                       if (month == -1)
+                               month = 1;
+                       if (year == -1) {
+                               if ((style & DateTimeStyles.NoCurrentDateDefault) != 0)
+                                       year = 1;
+                               else
+                                       year = Today.Year;
+                       }
+
+                       if (ampm == 1)
+                               hour = hour + 12;
+                       
+                       // For anything out of range 
+                       // return false
+                       if ( year < 1 || year > 9999 || 
+                       month < 1 || month >12  ||
+                       day < 1 || day > DaysInMonth(year, month) ||
+                       hour < 0 || hour > 23 ||
+                       minute < 0 || minute > 59 ||
+                       second < 0 || second > 59 )
+                               return false;
+
+                       result = new DateTime (year, month, day, hour, minute, second, 0);
+                       result = result.AddSeconds(fractionalSeconds);
+
+//Console.WriteLine ("**** Parsed as {1} {0} {2}", new object [] {useutc ? "[u]" : "", format, use_localtime ? "[lt]" : ""});
+                       if ((dayofweek != -1) && (dayofweek != (int) result.DayOfWeek))
+                               throw new FormatException (Locale.GetText ("String was not recognized as valid DateTime because the day of week was incorrect."));
+
+                       // If no timezone was specified, default to the local timezone.
+                       TimeSpan utcoffset;
+
+                       if (useutc)
+                               utcoffset = new TimeSpan (0, 0, 0);
+                       else if (tzsign == -1) {
+                               TimeZone tz = TimeZone.CurrentTimeZone;
+                               utcoffset = tz.GetUtcOffset (result);
+                       } else {
+                               if ((style & DateTimeStyles.AdjustToUniversal) != 0)
+                                       use_localtime = false;
+
+                               if (tzoffmin == -1)
+                                       tzoffmin = 0;
+                               if (tzoffset == -1)
+                                       tzoffset = 0;
+                               if (tzsign == 1)
+                                       tzoffset = -tzoffset;
+
+                               utcoffset = new TimeSpan (tzoffset, tzoffmin, 0);
+                       }
+
+                       long newticks = (result.ticks - utcoffset).Ticks;
+
+                       result = new DateTime (use_localtime, newticks);
+
+                       return true;
+               }
+
+
+               public static DateTime ParseExact (string s, string format,
+                                                  IFormatProvider fp, DateTimeStyles style)
+               {
+                       string[] formats;
+
+                       formats = new string [1];
+                       formats[0] = format;
+
+                       return ParseExact (s, formats, fp, style);
+               }
+
+               public static DateTime ParseExact (string s, string[] formats,
+                                                  IFormatProvider fp,
+                                                  DateTimeStyles style)
+               {
+                       DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (fp);
+
+                       if (s == null)
+                               throw new ArgumentNullException (Locale.GetText ("s is null"));
+                       if (formats == null || formats.Length == 0)
+                               throw new ArgumentNullException (Locale.GetText ("format is null"));
+
+                       DateTime result;
+                       bool longYear = false;
+                       if (!ParseExact (s, formats, dfi, style, out result, true, ref longYear))
+                               throw new FormatException ();
+                       return result;
+               }
+               
+               private static bool ParseExact (string s, string [] formats,
+                       DateTimeFormatInfo dfi, DateTimeStyles style, out DateTime ret,
+                       bool exact, ref bool longYear)
+               {
+                       int i;
+                       for (i = 0; i < formats.Length; i++)
+                       {
+                               DateTime result;
+
+                               if (_DoParse (s, formats[i], exact, out result, dfi, style, ref longYear)) {
+                                       ret = result;
+                                       return true;
+                               }
+                       }
+                       ret = DateTime.MinValue;
+                       return false;
+               }
+               
+               public TimeSpan Subtract(DateTime dt)
+               {   
+                       return new TimeSpan(ticks.Ticks) - dt.ticks;
+               }
+
+               public DateTime Subtract(TimeSpan ts)
+               {
+                       TimeSpan newticks;
+
+                       newticks = (new TimeSpan (ticks.Ticks)) - ts;
+                       return new DateTime(true,newticks);
+               }
+
+               public long ToFileTime()
+               {
+                       DateTime universalTime = ToUniversalTime();
+                       
+                       if (universalTime.Ticks < w32file_epoch) {
+                               throw new ArgumentOutOfRangeException("file time is not valid");
+                       }
+                       
+                       return(universalTime.Ticks - w32file_epoch);
+               }
+
+#if NET_1_1
+               public long ToFileTimeUtc()
+               {
+                       if (Ticks < w32file_epoch) {
+                               throw new ArgumentOutOfRangeException("file time is not valid");
+                       }
+                       
+                       return (Ticks - w32file_epoch);
+               }
+#endif
+
+               public string ToLongDateString()
+               {
+                       return ToString ("D");
+               }
+
+               public string ToLongTimeString()
+               {
+                       return ToString ("T");
+               }
+
+               public double ToOADate ()
+               {
+                       long t = this.Ticks;
+                       // uninitialized DateTime case
+                       if (t == 0)
+                               return 0;
+                       // we can't reach minimum value
+                       if (t < 31242239136000000)
+                               return OAMinValue + 0.001;
+
+                       TimeSpan ts = new TimeSpan (this.Ticks - ticks18991230);
+                       double result = ts.TotalDays;
+                       // t < 0 (where 599264352000000000 == 0.0d for OA)
+                       if (t < 599264352000000000) {
+                               // negative days (int) but decimals are positive
+                               double d = Math.Ceiling (result);
+                               result = d - 2 - (result - d);
+                       }
+                       else {
+                               // we can't reach maximum value
+                               if (result >= OAMaxValue)
+                                       result = OAMaxValue - 0.00000001d;
+                       }
+                       return result;
+               }
+
+               public string ToShortDateString()
+               {
+                       return ToString ("d");
+               }
+
+               public string ToShortTimeString()
+               {
+                       return ToString ("t");
+               }
+               
+               public override string ToString ()
+               {
+                       return ToString ("G", null);
+               }
+
+               public string ToString (IFormatProvider fp)
+               {
+                       return ToString (null, fp);
+               }
+
+               public string ToString (string format)
+               {
+                       return ToString (format, null);
+               }
+
+               internal static string _GetStandardPattern (char format, DateTimeFormatInfo dfi, out bool useutc, out bool use_invariant)
+               {
+                       String pattern;
+
+                       useutc = false;
+                       use_invariant = false;
+
+                       switch (format)
+                       {
+                       case 'd':
+                               pattern = dfi.ShortDatePattern;
+                               break;
+                       case 'D':
+                               pattern = dfi.LongDatePattern;
+                               break;
+                       case 'f':
+                               pattern = dfi.LongDatePattern + " " + dfi.ShortTimePattern;
+                               break;
+                       case 'F':
+                               pattern = dfi.FullDateTimePattern;
+                               break;
+                       case 'g':
+                               pattern = dfi.ShortDatePattern + " " + dfi.ShortTimePattern;
+                               break;
+                       case 'G':
+                               pattern = dfi.ShortDatePattern + " " + dfi.LongTimePattern;
+                               break;
+                       case 'm':
+                       case 'M':
+                               pattern = dfi.MonthDayPattern;
+                               break;
+                       case 'r':
+                       case 'R':
+                               pattern = dfi.RFC1123Pattern;
+                               // commented by LP 09/jun/2002, rfc 1123 pattern is always in GMT
+                               // uncommented by AE 27/may/2004
+//                             useutc = true;
+                               use_invariant = true;
+                               break;
+                       case 's':
+                               pattern = dfi.SortableDateTimePattern;
+                               break;
+                       case 't':
+                               pattern = dfi.ShortTimePattern;
+                               break;
+                       case 'T':
+                               pattern = dfi.LongTimePattern;
+                               break;
+                       case 'u':
+                               pattern = dfi.UniversalSortableDateTimePattern;
+                               useutc = true;
+                               break;
+                       case 'U':
+//                             pattern = dfi.LongDatePattern + " " + dfi.LongTimePattern;
+                               pattern = dfi.FullDateTimePattern;
+                               useutc = true;
+                               break;
+                       case 'y':
+                       case 'Y':
+                               pattern = dfi.YearMonthPattern;
+                               break;
+                       default:
+                               pattern = null;
+                               break;
+                       }
+
+                       return pattern;
+               }
+
+               internal string _ToString (string format, DateTimeFormatInfo dfi)
+               {
+                       // the length of the format is usually a good guess of the number
+                       // of chars in the result. Might save us a few bytes sometimes
+                       // Add + 10 for cases like mmmm dddd
+                       StringBuilder result = new StringBuilder (format.Length + 10);
+
+                       // For some cases, the output should not use culture dependent calendar
+                       DateTimeFormatInfo inv = DateTimeFormatInfo.InvariantInfo;
+                       if (format == inv.RFC1123Pattern)
+                               dfi = inv;
+                       else if (format == inv.UniversalSortableDateTimePattern)
+                               dfi = inv;
+
+                       int i = 0;
+
+                       while (i < format.Length) {
+                               int tokLen;
+                               char ch = format [i];
+
+                               switch (ch) {
+
+                               //
+                               // Time Formats
+                               //
+                               case 'h':
+                                       // hour, [1, 12]
+                                       tokLen = CountRepeat (format, i, ch);
+
+                                       int hr = this.Hour % 12;
+                                       if (hr == 0)
+                                               hr = 12;
+
+                                       ZeroPad (result, hr, tokLen == 1 ? 1 : 2);
+                                       break;
+                               case 'H':
+                                       // hour, [0, 23]
+                                       tokLen = CountRepeat (format, i, ch);
+                                       ZeroPad (result, this.Hour, tokLen == 1 ? 1 : 2);
+                                       break;
+                               case 'm':
+                                       // minute, [0, 59]
+                                       tokLen = CountRepeat (format, i, ch);
+                                       ZeroPad (result, this.Minute, tokLen == 1 ? 1 : 2);
+                                       break;
+                               case 's':
+                                       // second [0, 29]
+                                       tokLen = CountRepeat (format, i, ch);
+                                       ZeroPad (result, this.Second, tokLen == 1 ? 1 : 2);
+                                       break;
+                               case 'f':
+                                       // fraction of second, to same number of
+                                       // digits as there are f's
+
+                                       tokLen = CountRepeat (format, i, ch);
+                                       if (tokLen > 7)
+                                               throw new FormatException ("Invalid Format String");
+
+                                       int dec = (int)((long)(this.Ticks % TimeSpan.TicksPerSecond) / (long) Math.Pow (10, 7 - tokLen));
+                                       ZeroPad (result, dec, tokLen);
+
+                                       break;
+                               case 't':
+                                       // AM/PM. t == first char, tt+ == full
+                                       tokLen = CountRepeat (format, i, ch);
+                                       string desig = this.Hour < 12 ? dfi.AMDesignator : dfi.PMDesignator;
+
+                                       if (tokLen == 1) {
+                                               if (desig.Length >= 1)
+                                                       result.Append (desig [0]);
+                                       }
+                                       else
+                                               result.Append (desig);
+
+                                       break;
+                               case 'z':
+                                       // timezone. t = +/-h; tt = +/-hh; ttt+=+/-hh:mm
+                                       tokLen = CountRepeat (format, i, ch);
+                                       TimeSpan offset = TimeZone.CurrentTimeZone.GetUtcOffset (this);
+
+                                       if (offset.Ticks >= 0)
+                                               result.Append ('+');
+                                       else
+                                               result.Append ('-');
+
+                                       switch (tokLen) {
+                                       case 1:
+                                               result.Append (Math.Abs (offset.Hours));
+                                               break;
+                                       case 2:
+                                               result.Append (Math.Abs (offset.Hours).ToString ("00"));
+                                               break;
+                                       default:
+                                               result.Append (Math.Abs (offset.Hours).ToString ("00"));
+                                               result.Append (':');
+                                               result.Append (Math.Abs (offset.Minutes).ToString ("00"));
+                                               break;
+                                       }
+                                       break;
+                               //
+                               // Date tokens
+                               //
+                               case 'd':
+                                       // day. d(d?) = day of month (leading 0 if two d's)
+                                       // ddd = three leter day of week
+                                       // dddd+ full day-of-week
+                                       tokLen = CountRepeat (format, i, ch);
+
+                                       if (tokLen <= 2)
+                                               ZeroPad (result, dfi.Calendar.GetDayOfMonth (this), tokLen == 1 ? 1 : 2);
+                                       else if (tokLen == 3)
+                                               result.Append (dfi.GetAbbreviatedDayName (dfi.Calendar.GetDayOfWeek (this)));
+                                       else
+                                               result.Append (dfi.GetDayName (dfi.Calendar.GetDayOfWeek (this)));
+
+                                       break;
+                               case 'M':
+                                       // Month.m(m?) = month # (with leading 0 if two mm)
+                                       // mmm = 3 letter name
+                                       // mmmm+ = full name
+                                       tokLen = CountRepeat (format, i, ch);
+                                       int month = dfi.Calendar.GetMonth(this);
+                                       if (tokLen <= 2)
+                                               ZeroPad (result, month, tokLen);
+                                       else if (tokLen == 3)
+                                               result.Append (dfi.GetAbbreviatedMonthName (month));
+                                       else
+                                               result.Append (dfi.GetMonthName (month));
+
+                                       break;
+                               case 'y':
+                                       // Year. y(y?) = two digit year, with leading 0 if yy
+                                       // yyy+ full year, if yyy and yr < 1000, displayed as three digits
+                                       tokLen = CountRepeat (format, i, ch);
+
+                                       if (tokLen <= 2)
+                                               ZeroPad (result, dfi.Calendar.GetYear (this) % 100, tokLen);
+                                       else
+                                               ZeroPad (result, dfi.Calendar.GetYear (this), (tokLen == 3 ? 3 : 4));
+
+                                       break;
+                               case 'g':
+                                       // Era name
+                                       tokLen = CountRepeat (format, i, ch);
+                                       result.Append (dfi.GetEraName (dfi.Calendar.GetEra (this)));
+                                       break;
+
+                               //
+                               // Other
+                               //
+                               case ':':
+                                       result.Append (dfi.TimeSeparator);
+                                       tokLen = 1;
+                                       break;
+                               case '/':
+                                       result.Append (dfi.DateSeparator);
+                                       tokLen = 1;
+                                       break;
+                               case '\'': case '"':
+                                       tokLen = ParseQuotedString (format, i, result);
+                                       break;
+                               case '%':
+                                       if (i >= format.Length - 1)
+                                               throw new FormatException ("% at end of date time string");
+                                       if (format [i + 1] == '%')
+                                               throw new FormatException ("%% in date string");
+
+                                       // Look for the next char
+                                       tokLen = 1;
+                                       break;
+                               case '\\':
+                                       // C-Style escape
+                                       if (i >= format.Length - 1)
+                                               throw new FormatException ("\\ at end of date time string");
+
+                                       result.Append (format [i + 1]);
+                                       tokLen = 2;
+
+                                       break;
+                               default:
+                                       // catch all
+                                       result.Append (ch);
+                                       tokLen = 1;
+                                       break;
+                               }
+                               i += tokLen;
+                       }
+                       return result.ToString ();
+               }
+               
+               static int CountRepeat (string fmt, int p, char c)
+               {
+                       int l = fmt.Length;
+                       int i = p + 1;
+                       while ((i < l) && (fmt [i] == c)) 
+                               i++;
+                       
+                       return i - p;
+               }
+               
+               static int ParseQuotedString (string fmt, int pos, StringBuilder output)
+               {
+                       // pos == position of " or '
+                       
+                       int len = fmt.Length;
+                       int start = pos;
+                       char quoteChar = fmt [pos++];
+                       
+                       while (pos < len) {
+                               char ch = fmt [pos++];
+                               
+                               if (ch == quoteChar)
+                                       return pos - start;
+                               
+                               if (ch == '\\') {
+                                       // C-Style escape
+                                       if (pos >= len)
+                                               throw new FormatException("Un-ended quote");
+       
+                                       output.Append (fmt [pos++]);
+                               } else {
+                                       output.Append (ch);
+                               }
+                       }
+
+                       throw new FormatException("Un-ended quote");
+               }
+               
+               static unsafe void ZeroPad (StringBuilder output, int digits, int len)
+               {
+                       // more than enough for an int
+                       char* buffer = stackalloc char [16];
+                       int pos = 16;
+                       
+                       do {
+                               buffer [-- pos] = (char) ('0' + digits % 10);
+                               digits /= 10;
+                               len --;
+                       } while (digits > 0);
+                       
+                       while (len -- > 0)
+                               buffer [-- pos] = '0';
+                       
+                       output.Append (new string (buffer, pos, 16 - pos));
+               }
+
+               public string ToString (string format, IFormatProvider fp)
+
+               {
+                       DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance(fp);
+
+                       if (format == null)
+                               format = "G";
+
+                       bool useutc = false, use_invariant = false;
+
+                       if (format.Length == 1) {
+                               char fchar = format [0];
+                               format = _GetStandardPattern (fchar, dfi, out useutc, out use_invariant);
+                       }
+
+                       // Don't convert UTC value. It just adds 'Z' for 
+                       // 'u' format, for the same ticks.
+                       return this._ToString (format, dfi);
+               }
+
+               public DateTime ToLocalTime()
+               {
+                       TimeZone tz = TimeZone.CurrentTimeZone;
+
+                       TimeSpan offset = tz.GetUtcOffset (this);
+
+                       if (offset.Ticks > 0) {
+                               if (DateTime.MaxValue - offset < this)
+                                       return DateTime.MaxValue;
+                       } else if (offset.Ticks < 0) {
+                               // MS.NET fails to check validity here 
+                               // - it may throw ArgumentOutOfRangeException
+                               /*
+                               if (DateTime.MinValue - offset > this)
+                                       return DateTime.MinValue;
+                               */
+                       }
+                       
+                       DateTime lt = new DateTime(true, ticks+offset);
+                       TimeSpan ltoffset = tz.GetUtcOffset(lt);
+                       if(ltoffset != offset)
+                               lt = lt.Add(ltoffset.Subtract(offset));
+
+                       return lt;
+               }
+
+               public DateTime ToUniversalTime()
+               {
+                       TimeZone tz = TimeZone.CurrentTimeZone;
+
+                       TimeSpan offset = tz.GetUtcOffset (this);
+
+                       if (offset.Ticks < 0) {
+                               if (DateTime.MaxValue + offset < this)
+                                       return DateTime.MaxValue;
+                       } else if (offset.Ticks > 0) {
+                               if (DateTime.MinValue + offset > this)
+                                       return DateTime.MinValue;
+                       }
+
+                       return new DateTime (false, ticks - offset);
+               }
+
+               /*  OPERATORS */
+
+               public static DateTime operator +(DateTime d, TimeSpan t)
+               {
+                       return new DateTime (true, d.ticks + t);
+               }
+
+               public static bool operator ==(DateTime d1, DateTime d2)
+               {
+                       return (d1.ticks == d2.ticks);
+               }
+
+               public static bool operator >(DateTime t1,DateTime t2)
+               {
+                       return (t1.ticks > t2.ticks);
+               }
+
+               public static bool operator >=(DateTime t1,DateTime t2)
+               {
+                       return (t1.ticks >= t2.ticks);
+               }
+
+               public static bool operator !=(DateTime d1, DateTime d2)
+               {
+                       return (d1.ticks != d2.ticks);
+               }
+
+               public static bool operator <(DateTime t1,      DateTime t2)
+               {
+                       return (t1.ticks < t2.ticks );
+               }
+
+               public static bool operator <=(DateTime t1,DateTime t2)
+               {
+                       return (t1.ticks <= t2.ticks);
+               }
+
+               public static TimeSpan operator -(DateTime d1,DateTime d2)
+               {
+                       return new TimeSpan((d1.ticks - d2.ticks).Ticks);
+               }
+
+               public static DateTime operator -(DateTime d,TimeSpan t)
+               {
+                       return new DateTime (true, d.ticks - t);
+               }
+
+               bool IConvertible.ToBoolean(IFormatProvider provider)
+               {
+                       throw new InvalidCastException();
+               }
+               
+               byte IConvertible.ToByte(IFormatProvider provider)
+               {
+                       throw new InvalidCastException();
+
+               }
+
+               char IConvertible.ToChar(IFormatProvider provider)
+               {
+                       throw new InvalidCastException();
+               }
+
+               System.DateTime IConvertible.ToDateTime(IFormatProvider provider)
+               {
+                       return this;
+               } 
+               
+               decimal IConvertible.ToDecimal(IFormatProvider provider)
+               {
+                        throw new InvalidCastException();
+               }
+
+               double IConvertible.ToDouble(IFormatProvider provider)
+               {
+                       throw new InvalidCastException();
+               }
+
+               Int16 IConvertible.ToInt16(IFormatProvider provider)
+               {
+                       throw new InvalidCastException();
+               }
+
+               Int32 IConvertible.ToInt32(IFormatProvider provider)
+               {
+                       throw new InvalidCastException();
+               }
+
+               Int64 IConvertible.ToInt64(IFormatProvider provider)
+               {
+                       throw new InvalidCastException();
+               }
+
+               SByte IConvertible.ToSByte(IFormatProvider provider)
+               {
+                       throw new InvalidCastException();
+               }
+
+               Single IConvertible.ToSingle(IFormatProvider provider)
+               {
+                       throw new InvalidCastException();
+               }
+
+               object IConvertible.ToType (Type conversionType, IFormatProvider provider)
+               {
+                       if (conversionType == null)
+                               throw new ArgumentNullException ("conversionType");
+
+                       if (conversionType == typeof (DateTime))
+                               return this;
+                       else if (conversionType == typeof (String))
+                               return this.ToString (provider);
+                       else if (conversionType == typeof (Object))
+                               return this;
+                       else
+                               throw new InvalidCastException();
+               }
+
+               UInt16 IConvertible.ToUInt16(IFormatProvider provider)
+               {
+                       throw new InvalidCastException();
+               }
+               
+               UInt32 IConvertible.ToUInt32(IFormatProvider provider)
+               {
+                       throw new InvalidCastException();
+               }
+
+               UInt64 IConvertible.ToUInt64(IFormatProvider provider)
+               {
+                       throw new InvalidCastException();
+               }
+       }
+}
+
+namespace System
+{
+       public enum DayOfWeek
+       {
+               Sunday,
+               Monday,
+               Tuesday,
+               Wednesday,
+               Thursday,
+               Friday,
+               Saturday
+       }
+}