New tests.
[mono.git] / mcs / class / corlib / System / DateTime.cs
index 7c4f5963eface7ed458760ab7d83c31ac79f0641..94c8a73a63577e7ab524aa04daeba40c501d7734 100644 (file)
@@ -7,7 +7,7 @@
 //   Atsushi Enomoto (atsushi@ximian.com)
 //
 //   (C) 2001 Marcel Narings
-// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004-2006 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
@@ -34,6 +34,7 @@ using System.Globalization;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Text;
+using System.Runtime.Serialization;
 
 namespace System
 {
@@ -44,16 +45,19 @@ namespace System
        /// 
        [Serializable]
        [StructLayout (LayoutKind.Auto)]
-       public struct DateTime : IFormattable, IConvertible, IComparable
-#if NET_2_0
-               , IComparable<DateTime>, IEquatable <DateTime>
-#endif
+       public struct DateTime : IFormattable, IConvertible, IComparable, ISerializable, IComparable<DateTime>, IEquatable <DateTime>
        {
+#if MONOTOUCH
+               static DateTime () {
+                       if (MonoTouchAOTHelper.FalseFlag) {
+                               var comparer = new System.Collections.Generic.GenericComparer <DateTime> ();
+                               var eqcomparer = new System.Collections.Generic.GenericEqualityComparer <DateTime> ();
+                       }
+               }
+#endif
                private TimeSpan ticks;
 
-#if NET_2_0
                DateTimeKind kind;
-#endif
 
                private const int dp400 = 146097;
                private const int dp100 = 36524;
@@ -81,82 +85,114 @@ namespace System
                public static readonly DateTime MaxValue = new DateTime (false, new TimeSpan (MAX_VALUE_TICKS));
                public static readonly DateTime MinValue = new DateTime (false, new TimeSpan (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",
-                       // bug #78618
-                       "yyyy-M-d H:m:s.fffffff",
-                       // 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'",
-                       // bug #53023
-                       "MM/dd/yyyy",
-                       // 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", 
-
-                       // bug #60912
-                       "M/d/yyyy HH':'mm':'ss tt",
-                       "H':'mm':'ss tt",
-                       // another funky COM dependent one
-                       "dd-MMM-yy",
-
-                       // DayOfTheWeek, dd full_month_name yyyy
-                       // FIXME: 1054(th-TH) rejects them
-                       "dddd, dd MMMM yyyy",
-                       "dddd, dd MMMM yyyy HH:mm",
-                       "dddd, dd MMMM yyyy HH:mm:ss",
-
-                       "yyyy MMMM",
-                       // 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'",
-
-                       // Additionally there seems language-specific format
-                       // patterns that however works in all language
-                       // environment.
-                       // For example, the pattern below is for Japanese.
-                       "yyyy'\u5E74'MM'\u6708'dd'\u65E5' HH'\u6642'mm'\u5206'ss'\u79D2'",
-
-/*
-                       // 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" 
-*/
+               // DateTime.Parse patterns
+               // Patterns are divided to date and time patterns. The algorithm will
+               // try combinations of these patterns. The algorithm also looks for
+               // day of the week, AM/PM GMT and Z independently of the patterns.
+               private static readonly string[] ParseTimeFormats = new string [] {
+                       "H:m:s.fffffffzzz",
+                       "H:m:s.fffffff",
+                       "H:m:s tt zzz",
+                       "H:m:szzz",
+                       "H:m:s",
+                       "H:mzzz",
+                       "H:m",
+                       "H tt", // Specifies AM to disallow '8'.
+                       "H'\u6642'm'\u5206's'\u79D2'",
+               };
+
+               // DateTime.Parse date patterns extend ParseExact patterns as follows:
+               //   MMM - month short name or month full name
+               //   MMMM - month number or short name or month full name
+
+               // Parse behaves differently according to the ShorDatePattern of the
+               // DateTimeFormatInfo. The following define the date patterns for
+               // different orders of day, month and year in ShorDatePattern.
+               // Note that the year cannot go between the day and the month.
+               private static readonly string[] ParseYearDayMonthFormats = new string [] {
+                       "yyyy/M/dT",
+                       "M/yyyy/dT",
+                       "yyyy'\u5E74'M'\u6708'd'\u65E5",
+
+
+                       "yyyy/d/MMMM",
+                       "yyyy/MMM/d",
+                       "d/MMMM/yyyy",
+                       "MMM/d/yyyy",
+                       "d/yyyy/MMMM",
+                       "MMM/yyyy/d",
+
+                       "yy/d/M",
+               };
+
+               private static readonly string[] ParseYearMonthDayFormats = new string [] {
+                       "yyyy/M/dT",
+                       "M/yyyy/dT",
+                       "yyyy'\u5E74'M'\u6708'd'\u65E5",
+
+                       "yyyy/MMMM/d",
+                       "yyyy/d/MMM",
+                       "MMMM/d/yyyy",
+                       "d/MMM/yyyy",
+                       "MMMM/yyyy/d",
+                       "d/yyyy/MMM",
+
+                       "yy/MMMM/d",
+                       "yy/d/MMM",
+                       "MMM/yy/d",
+               };
+
+               private static readonly string[] ParseDayMonthYearFormats = new string [] {
+                       "yyyy/M/dT",
+                       "M/yyyy/dT",
+                       "yyyy'\u5E74'M'\u6708'd'\u65E5",
+
+                       "yyyy/MMMM/d",
+                       "yyyy/d/MMM",
+                       "d/MMMM/yyyy",
+                       "MMM/d/yyyy",
+                       "MMMM/yyyy/d",
+                       "d/yyyy/MMM",
+
+                       "d/MMMM/yy",
+                       "yy/MMM/d",
+                       "d/yy/MMM",
+                       "yy/d/MMM",
+                       "MMM/d/yy",
+                       "MMM/yy/d",
+               };
+
+               private static readonly string[] ParseMonthDayYearFormats = new string [] {
+                       "yyyy/M/dT",
+                       "M/yyyy/dT",
+                       "yyyy'\u5E74'M'\u6708'd'\u65E5",
+
+                       "yyyy/MMMM/d",
+                       "yyyy/d/MMM",
+                       "MMMM/d/yyyy",
+                       "d/MMM/yyyy",
+                       "MMMM/yyyy/d",
+                       "d/yyyy/MMM",
+
+                       "MMMM/d/yy",
+                       "MMM/yy/d",
+                       "d/MMM/yy",
+                       "yy/MMM/d",
+                       "d/yy/MMM",
+                       "yy/d/MMM",
+               };
+
+               // Patterns influenced by the MonthDayPattern in DateTimeFormatInfo.
+               // Note that these patterns cannot be followed by the time.
+               private static readonly string[] MonthDayShortFormats = new string [] {
+                       "MMMM/d",
+                       "d/MMM",
+                       "yyyy/MMMM",
+               };
+               private static readonly string[] DayMonthShortFormats = new string [] {
+                       "d/MMMM",
+                       "MMM/yy",
+                       "yyyy/MMMM",
                };
 
                private enum Which 
@@ -214,7 +250,7 @@ namespace System
                        
                        if  ((numyears==3) && ((num100 == 3) || !(num4 == 24)) ) //31 dec leapyear
                                days = daysmonthleap;
-                               
+
                        while (totaldays >= days[M])
                                totaldays -= days[M++];
 
@@ -239,9 +275,7 @@ namespace System
                                        ticks, MinValue.Ticks, MaxValue.Ticks);
                                throw new ArgumentOutOfRangeException ("ticks", msg);
                        }
-#if NET_2_0
                        kind = DateTimeKind.Unspecified;
-#endif
                }
 
                public DateTime (int year, int month, int day)
@@ -264,45 +298,37 @@ namespace System
 
                        ticks = new TimeSpan (AbsoluteDays(year,month,day), hour, minute, second, millisecond);
 
-#if NET_2_0
                        kind = DateTimeKind.Unspecified;
-#endif
                }
 
-               [MonoTODO ("Calendar is unused")]
                public DateTime (int year, int month, int day, Calendar calendar)
                        : this (year, month, day, 0, 0, 0, 0, calendar)
                {
                }
                
-               [MonoTODO ("Calendar is unused")]
                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)
                {
                }
 
-               [MonoTODO ("Calendar is unused")]
                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 ("calendar");
-                       // FIXME: we're not using the calendar anywhere???
+                       ticks = calendar.ToDateTime (year, month, day, hour, minute, second, millisecond).ticks;
+                       kind = DateTimeKind.Unspecified;
                }
 
                internal DateTime (bool check, TimeSpan value)
                {
                        if (check && (value.Ticks < MinValue.Ticks || value.Ticks > MaxValue.Ticks))
-                           throw new ArgumentOutOfRangeException ();
+                               throw new ArgumentOutOfRangeException ();
 
                        ticks = value;
 
-#if NET_2_0
                        kind = DateTimeKind.Unspecified;
-#endif
                }
 
-#if NET_2_0
                public DateTime (long ticks, DateTimeKind kind) : this (ticks)
                {
                        CheckDateTimeKind (kind);
@@ -328,19 +354,39 @@ namespace System
                {
                        CheckDateTimeKind (kind);
                        this.kind = kind;
-               }                       
-#endif
+               }
 
+               //
+               // Not visible, but can be invoked during deserialization
+               //
+               DateTime (SerializationInfo info, StreamingContext context)
+               {
+                       if (info.HasKey ("dateData")){
+                               long dateData = info.GetInt64 ("dateData");
+                               kind = (DateTimeKind) (dateData >> 62);
+                               ticks = new TimeSpan (dateData & 0x3fffffffffffffff);
+                       } else if (info.HasKey ("ticks")){
+                               ticks = new TimeSpan (info.GetInt64 ("ticks"));
+                               kind = DateTimeKind.Unspecified;
+                       } else {
+                               kind = DateTimeKind.Unspecified;
+                               ticks = new TimeSpan (0);
+                       }
+               }
+               
+                             
                /* Properties  */
 
                public DateTime Date 
                {
                        get     
                        { 
-                               return new DateTime (Year, Month, Day);
+                               DateTime ret = new DateTime (Year, Month, Day);
+                               ret.kind = kind;
+                               return ret;
                        }
                }
-        
+
                public int Month 
                {
                        get     
@@ -349,7 +395,6 @@ namespace System
                        }
                }
 
-              
                public int Day
                {
                        get 
@@ -415,14 +460,38 @@ namespace System
                        }
                }
                
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               internal static extern long GetTimeMonotonic ();
+
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                internal static extern long GetNow ();
 
+               //
+               // To reduce the time consumed by DateTime.Now, we keep
+               // the difference to map the system time into a local
+               // time into `to_local_time_span', we record the timestamp
+               // for this in `last_now'
+               //
+               static object to_local_time_span_object;
+               static long last_now;
+               
                public static DateTime Now 
                {
                        get     
                        {
-                               return new DateTime (GetNow ()).ToLocalTime ();
+                               long now = GetNow ();
+                               DateTime dt = new DateTime (now);
+
+                               if ((now - last_now) > TimeSpan.TicksPerMinute){
+                                       to_local_time_span_object = TimeZone.CurrentTimeZone.GetLocalTimeDiff (dt);
+                                       last_now = now;
+
+                               }
+
+                               // This is boxed, so we avoid locking.
+                               DateTime ret = dt + (TimeSpan) to_local_time_span_object;
+                               ret.kind = DateTimeKind.Local;
+                               return ret;
                        }
                }
 
@@ -439,9 +508,7 @@ namespace System
                        get {
                                DateTime now = Now;
                                DateTime today = new DateTime (now.Year, now.Month, now.Day);
-#if NET_2_0
                                today.kind = now.kind;
-#endif
                                return today;
                        }
                }
@@ -449,11 +516,7 @@ namespace System
                public static DateTime UtcNow 
                {
                        get {
-#if NET_2_0
                                return new DateTime (GetNow (), DateTimeKind.Utc);
-#else
-                               return new DateTime (GetNow ());
-#endif
                        }
                }
 
@@ -465,46 +528,48 @@ namespace System
                        }
                }
 
-#if NET_2_0
                public DateTimeKind Kind {
                        get {
                                return kind;
                        }
                }
-#endif
 
                /* methods */
 
-               public DateTime Add (TimeSpan ts)
+               public DateTime Add (TimeSpan value)
                {
-                       return AddTicks (ts.Ticks);
+                       DateTime ret = AddTicks (value.Ticks);
+                       ret.kind = kind;
+                       return ret;
                }
 
-               public DateTime AddDays (double days)
+               public DateTime AddDays (double value)
                {
-                       return AddMilliseconds (Math.Round (days * 86400000));
+                       return AddMilliseconds (Math.Round (value * 86400000));
                }
                
-               public DateTime AddTicks (long t)
+               public DateTime AddTicks (long value)
                {
-                       if ((t + ticks.Ticks) > MAX_VALUE_TICKS || (t + ticks.Ticks) < 0) {
+                       if ((value + ticks.Ticks) > MAX_VALUE_TICKS || (value + ticks.Ticks) < 0) {
                                throw new ArgumentOutOfRangeException();
                        }
-                       return new DateTime (t + ticks.Ticks);
+                       DateTime ret = new DateTime (value + ticks.Ticks);
+                       ret.kind = kind;
+                       return ret;
                }
 
-               public DateTime AddHours (double hours)
+               public DateTime AddHours (double value)
                {
-                       return AddMilliseconds (hours * 3600000);
+                       return AddMilliseconds (value * 3600000);
                }
 
-               public DateTime AddMilliseconds (double ms)
+               public DateTime AddMilliseconds (double value)
                {
-                       if ((ms * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
-                                       (ms * TimeSpan.TicksPerMillisecond) < long.MinValue) {
+                       if ((value * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
+                                       (value * TimeSpan.TicksPerMillisecond) < long.MinValue) {
                                throw new ArgumentOutOfRangeException();
                        }
-                       long msticks = (long) (ms * TimeSpan.TicksPerMillisecond);
+                       long msticks = (long) Math.Round (value * TimeSpan.TicksPerMillisecond);
 
                        return AddTicks (msticks);
                }
@@ -521,9 +586,9 @@ namespace System
                        return AddTicks (msticks);
                }
 
-               public DateTime AddMinutes (double minutes)
+               public DateTime AddMinutes (double value)
                {
-                       return AddMilliseconds (minutes * 60000);
+                       return AddMilliseconds (value * 60000);
                }
                
                public DateTime AddMonths (int months)
@@ -550,17 +615,18 @@ namespace System
                                day = maxday;
 
                        temp = new DateTime (year, month, day);
+                       temp.kind = kind;
                        return  temp.Add (this.TimeOfDay);
                }
 
-               public DateTime AddSeconds (double seconds)
+               public DateTime AddSeconds (double value)
                {
-                       return AddMilliseconds (seconds*1000);
+                       return AddMilliseconds (value * 1000);
                }
 
-               public DateTime AddYears (int years )
+               public DateTime AddYears (int value)
                {
-                       return AddMonths(years * 12);
+                       return AddMonths (value * 12);
                }
 
                public static int Compare (DateTime t1, DateTime t2)
@@ -573,19 +639,18 @@ namespace System
                                return 0;
                }
 
-               public int CompareTo (object v)
+               public int CompareTo (object value)
                {
-                       if ( v == null)
+                       if (value == null)
                                return 1;
 
-                       if (!(v is System.DateTime))
+                       if (!(value is System.DateTime))
                                throw new ArgumentException (Locale.GetText (
                                        "Value is not a System.DateTime"));
 
-                       return Compare (this, (DateTime) v);
+                       return Compare (this, (DateTime) value);
                }
 
-#if NET_2_0
                public bool IsDaylightSavingTime ()
                {
                        if (kind == DateTimeKind.Utc)
@@ -603,11 +668,34 @@ namespace System
                        return value.ticks == ticks;
                }
 
+               public long ToBinary ()
+               {
+                       switch (kind) {
+                       case DateTimeKind.Utc:
+                               return Ticks | 0x4000000000000000;
+                       case DateTimeKind.Local:
+                               return (long) ((ulong) ToUniversalTime ().Ticks | 0x8000000000000000);
+                       default:
+                               return Ticks;
+                       }
+               }
+
+               public static DateTime FromBinary (long dateData)
+               {
+                       switch ((ulong)dateData >> 62) {
+                       case 1:
+                               return new DateTime (dateData ^ 0x4000000000000000, DateTimeKind.Utc);
+                       case 0:
+                               return new DateTime (dateData, DateTimeKind.Unspecified);
+                       default:
+                               return new DateTime (dateData & 0x3fffffffffffffff, DateTimeKind.Utc).ToLocalTime ();
+                       }
+               }
+
                public static DateTime SpecifyKind (DateTime value, DateTimeKind kind)
                {
                        return new DateTime (value.Ticks, kind);
                }
-#endif
 
                public static int DaysInMonth (int year, int month)
                {
@@ -616,16 +704,19 @@ namespace System
                        if (month < 1 || month >12)
                                throw new ArgumentOutOfRangeException ();
 
+                       if (year < 1 || year > 9999)
+                               throw new ArgumentOutOfRangeException ();
+
                        days = (IsLeapYear(year) ? daysmonthleap  : daysmonth);
                        return days[month];                     
                }
                
-               public override bool Equals (object o)
+               public override bool Equals (object value)
                {
-                       if (!(o is System.DateTime))
+                       if (!(value is System.DateTime))
                                return false;
 
-                       return ((DateTime) o).ticks == ticks;
+                       return ((DateTime) value).ticks == ticks;
                }
 
                public static bool Equals (DateTime t1, DateTime t2 )
@@ -641,7 +732,6 @@ namespace System
                        return new DateTime (w32file_epoch + fileTime).ToLocalTime ();
                }
 
-#if NET_1_1
                public static DateTime FromFileTimeUtc (long fileTime) 
                {
                        if (fileTime < 0)
@@ -649,7 +739,6 @@ namespace System
 
                        return new DateTime (w32file_epoch + fileTime);
                }
-#endif
 
                public static DateTime FromOADate (double d)
                {
@@ -720,7 +809,7 @@ namespace System
                                break;
                        }
                        DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
-                       return GetDateTimeFormats (adjustutc, info.GetAllDateTimePatterns (format), info);
+                       return GetDateTimeFormats (adjustutc, info.GetAllRawDateTimePatterns (format), info);
                }
 
                private string [] GetDateTimeFormats (bool adjustutc, string [] patterns, DateTimeFormatInfo dfi)
@@ -728,16 +817,14 @@ namespace System
                        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);
+                               results [i] = DateTimeUtils.ToString (val, patterns [i], dfi);
                        return results;
                }
 
-#if NET_2_0
                private void CheckDateTimeKind (DateTimeKind kind) {
                        if ((kind != DateTimeKind.Unspecified) && (kind != DateTimeKind.Utc) && (kind != DateTimeKind.Local))
                                throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
                }
-#endif
 
                public override int GetHashCode ()
                {
@@ -751,6 +838,8 @@ namespace System
 
                public static bool IsLeapYear (int year)
                {
+                       if (year < 1 || year > 9999)
+                               throw new ArgumentOutOfRangeException ();
                        return  ( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ;
                }
 
@@ -759,66 +848,162 @@ namespace System
                        return Parse (s, null);
                }
 
-               public static DateTime Parse (string s, IFormatProvider fp)
+               public static DateTime Parse (string s, IFormatProvider provider)
                {
-                       return Parse (s, fp, DateTimeStyles.AllowWhiteSpaces);
+                       return Parse (s, provider, DateTimeStyles.AllowWhiteSpaces);
                }
 
-               [MonoTODO ("see the comments inline")]
-               public static DateTime Parse (string s, IFormatProvider fp, DateTimeStyles styles)
+               public static DateTime Parse (string s, IFormatProvider provider, 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;
+                               throw new ArgumentNullException ("s");
 
-                       if (fp == null)
-                               fp = CultureInfo.CurrentCulture;
-                       DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (fp);
+                       DateTime res;
+                       DateTimeOffset dto;
+                       Exception exception = null;
+                       if (!CoreParse (s, provider, styles, out res, out dto, true, ref exception))
+                               throw exception;
+                       
+                       return res;
+               }
+
+               const string formatExceptionMessage = "String was not recognized as a valid DateTime.";
+               
+               internal static bool CoreParse (string s, IFormatProvider provider, DateTimeStyles styles,
+                                             out DateTime result, out DateTimeOffset dto, bool setExceptionOnError, ref Exception exception)
+               {
+                       dto = new DateTimeOffset (0, TimeSpan.Zero);
+                       if (s == null || s.Length == 0) {
+                               if (setExceptionOnError)
+                                       exception = new FormatException (formatExceptionMessage);
+                               result = MinValue;
+                               return false;
+                       }
+
+                       if (provider == null)
+                               provider = CultureInfo.CurrentCulture;
+                       DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
+
+                       // Try first all the combinations of ParseAllDateFormats & ParseTimeFormats
+                       string[] allDateFormats = YearMonthDayFormats (dfi, setExceptionOnError, ref exception);
+                       if (allDateFormats == null){
+                               result = MinValue;
+                               return false;
+                       }
 
                        bool longYear = false;
+                       for (int i = 0; i < allDateFormats.Length; i++) {
+                               string firstPart = allDateFormats [i];
+                               bool incompleteFormat = false;
+                               if (_DoParse (s, firstPart, "", false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
+                                       return true;
 
-                       // Try all the patterns
-                       if (ParseExact (s, dfi.GetAllDateTimePatternsInternal (), dfi, styles, out result, false, ref longYear))
-                               return result;
+                               if (!incompleteFormat)
+                                       continue;
 
-                       // Try common formats.
-//                     if (ParseExact (s, commonFormats, dfi, styles, out result, false, ref longYear))
-//                             return result;
+                               for (int j = 0; j < ParseTimeFormats.Length; j++) {
+                                       if (_DoParse (s, firstPart, ParseTimeFormats [j], false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
+                                               return true;
+                               }
+                       }
 
-                       // Try common formats with invariant culture
-                       if (ParseExact (s, commonFormats, DateTimeFormatInfo.InvariantInfo, styles, out result, false, ref longYear))
-                               return result;
+                       //
+                       // Month day formats
+                       //
+                       int dayIndex = dfi.MonthDayPattern.IndexOf('d');
+                       int monthIndex = dfi.MonthDayPattern.IndexOf('M');
+                       if (dayIndex == -1 || monthIndex == -1){
+                               result = MinValue;
+                               if (setExceptionOnError)
+                                       exception = new FormatException (Locale.GetText("Order of month and date is not defined by {0}", dfi.MonthDayPattern));
+                               return false;
+                       }
+                       bool is_day_before_month = dayIndex < monthIndex;
+                       string[] monthDayFormats = is_day_before_month ? DayMonthShortFormats : MonthDayShortFormats;
+                       for (int i = 0; i < monthDayFormats.Length; i++) {
+                               bool incompleteFormat = false;
+                               if (_DoParse (s, monthDayFormats[i], "", false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
+                                       return true;
+                       }
+                       
+                       for (int j = 0; j < ParseTimeFormats.Length; j++) {
+                               string firstPart = ParseTimeFormats [j];
+                               bool incompleteFormat = false;
+                               if (_DoParse (s, firstPart, "", false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
+                                       return true;
+                               if (!incompleteFormat)
+                                       continue;
 
-                       if (longYear) {
-                               throw new ArgumentOutOfRangeException ("year",
-                                       "Valid values are between 1 and 9999 inclusive");
+                               for (int i = 0; i < monthDayFormats.Length; i++) {
+                                       if (_DoParse (s, firstPart, monthDayFormats [i], false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
+                                               return true;
+                               }
+                               for (int i = 0; i < allDateFormats.Length; i++) {
+                                       string dateFormat = allDateFormats [i];
+                                       if (dateFormat[dateFormat.Length - 1] == 'T')
+                                               continue; // T formats must be before the time part
+                                       if (_DoParse (s, firstPart, dateFormat, false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
+                                               return true;
+                               }
                        }
 
-                       throw new FormatException ("String was not recognized as a valid DateTime.");
+                       // Try as a last resort all the patterns
+                       if (ParseExact (s, dfi.GetAllDateTimePatternsInternal (), dfi, styles, out result, false, ref longYear, setExceptionOnError, ref exception))
+                               return true;
+
+                       if (!setExceptionOnError)
+                               return false;
+                       
+                       // .NET 2.x does not throw an ArgumentOutOfRangeException, but .NET 1.1 does.
+                       exception = new FormatException (formatExceptionMessage);
+                       return false;
+               }
+
+               public static DateTime ParseExact (string s, string format, IFormatProvider provider)
+               {
+                       return ParseExact (s, format, provider, DateTimeStyles.None);
                }
 
-               public static DateTime ParseExact (string s, string format, IFormatProvider fp)
+               private static string[] YearMonthDayFormats (DateTimeFormatInfo dfi, bool setExceptionOnError, ref Exception exc)
                {
-                       return ParseExact (s, format, fp, DateTimeStyles.None);
+                       int dayIndex = dfi.ShortDatePattern.IndexOf('d');
+                       int monthIndex = dfi.ShortDatePattern.IndexOf('M');
+                       int yearIndex = dfi.ShortDatePattern.IndexOf('y');
+                       if (dayIndex == -1 || monthIndex == -1 || yearIndex == -1){
+                               if (setExceptionOnError)
+                                       exc = new FormatException (Locale.GetText("Order of year, month and date is not defined by {0}", dfi.ShortDatePattern));
+                               return null;
+                       }
+
+                       if (yearIndex < monthIndex)
+                               if (monthIndex < dayIndex)
+                                       return ParseYearMonthDayFormats;
+                               else if (yearIndex < dayIndex)
+                                       return ParseYearDayMonthFormats;
+                               else {
+                                       // The year cannot be between the date and the month
+                                       if (setExceptionOnError)
+                                               exc = new FormatException (Locale.GetText("Order of date, year and month defined by {0} is not supported", dfi.ShortDatePattern));
+                                       return null;
+                               }
+                       else if (dayIndex < monthIndex)
+                               return ParseDayMonthYearFormats;
+                       else if (dayIndex < yearIndex)
+                               return ParseMonthDayYearFormats;
+                       else {
+                               // The year cannot be between the month and the date
+                               if (setExceptionOnError)
+                                       exc = new FormatException (Locale.GetText("Order of month, year and date defined by {0} is not supported", dfi.ShortDatePattern));
+                               return null;
+                       }
                }
 
-               internal static int _ParseNumber (string s, int valuePos,
-                                                 int min_digits,
-                                                 int digits,
-                                                 bool leadingzero,
-                                                 bool sloppy_parsing,
-                                                 out int num_parsed)
+               private static int _ParseNumber (string s, int valuePos,
+                                                int min_digits,
+                                                int digits,
+                                                bool leadingzero,
+                                                bool sloppy_parsing,
+                                                out int num_parsed)
                {
                        int number = 0, i;
 
@@ -860,18 +1045,25 @@ namespace System
                        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;
+               private static int _ParseEnum (string s, int sPos, string[] values, string[] invValues, bool exact, out int num_parsed)
+               {
+                       // FIXME: I know this is somehow lame code. Probably
+                       // it should iterate all the enum value and return
+                       // the longest match. However right now I don't see
+                       // anything but "1" and "10" - "12" that might match
+                       // two or more values. (They are only abbrev month
+                       // names, so do reverse order search). See bug #80094.
+                       for (int i = values.Length - 1; i >= 0; i--) {
+                               if (!exact && invValues [i].Length > values[i].Length) {
+                                       if (invValues [i].Length > 0 && _ParseString (s, sPos, 0, invValues [i], out num_parsed))
+                                               return i;
+                                       if (values [i].Length > 0 && _ParseString (s, sPos, 0, values [i], out num_parsed))
+                                               return i;
+                               }
+                               else {
+                                       if (values [i].Length > 0 && _ParseString (s, sPos, 0, values [i], out num_parsed))
+                                               return i;
+                                       if (!exact && invValues [i].Length > 0 && _ParseString (s, sPos, 0, invValues [i], out num_parsed))
                                        return i;
                                }
                        }
@@ -880,12 +1072,12 @@ namespace System
                        return -1;
                }
 
-               internal static bool _ParseString (string s, int sPos, int maxlength, string value, out int num_parsed)
+               private 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) {
+                       if (sPos + maxlength <= s.Length && String.Compare (s, sPos, value, 0, maxlength, true, CultureInfo.InvariantCulture) == 0) {
                                num_parsed = maxlength;
                                return true;
                        }
@@ -894,21 +1086,108 @@ namespace System
                        return false;
                }
 
-               private static bool _DoParse (string s, string format, bool exact,
-                                              out DateTime result,
+               // Note that in case of Parse (exact == false) we check both for AM/PM
+               // and the culture spcific AM/PM strings.
+               private static bool _ParseAmPm(string s,
+                                              int valuePos,
+                                              int num,
                                               DateTimeFormatInfo dfi,
-                                              DateTimeStyles style,
-                                              ref bool longYear)
+                                              bool exact,
+                                              out int num_parsed,
+                                              ref int ampm)
+               {
+                       num_parsed = -1;
+                       if (ampm != -1)
+                               return false;
+
+                       if (!IsLetter (s, valuePos)) {
+                               if (dfi.AMDesignator != "")
+                                       return false;
+                               if (exact)
+                                       ampm = 0;
+                               num_parsed = 0;
+                               return true;
+                       }
+                       DateTimeFormatInfo invInfo = DateTimeFormatInfo.InvariantInfo;
+                       if (!exact && _ParseString (s, valuePos, num, invInfo.PMDesignator, out num_parsed) ||
+                           dfi.PMDesignator != "" && _ParseString(s, valuePos, num, dfi.PMDesignator, out num_parsed))
+                               ampm = 1;
+                       else if (!exact && _ParseString (s, valuePos, num, invInfo.AMDesignator, out num_parsed) ||
+                                _ParseString (s, valuePos, num, dfi.AMDesignator, out num_parsed)) {
+                               if (exact || num_parsed != 0)
+                                       ampm = 0;
+                       }
+                       else
+                               return false;
+                       return true;
+               }
+
+               // Note that in case of Parse (exact == false) we check both for ':'
+               // and the culture spcific TimeSperator
+               private static bool _ParseTimeSeparator (string s, int sPos, DateTimeFormatInfo dfi, bool exact, out int num_parsed)
                {
-                       bool useutc = false, use_localtime = true;
+                       return _ParseString (s, sPos, 0, dfi.TimeSeparator, out num_parsed) ||
+                              !exact && _ParseString (s, sPos, 0, ":", out num_parsed);
+               }
+
+               // Accept any character for DateSeparator, except TimeSeparator,
+               // a digit or a letter.
+               // Not documented, but seems to be MS behaviour here.  See bug 54047.
+               private static bool _ParseDateSeparator (string s, int sPos, DateTimeFormatInfo dfi, bool exact, out int num_parsed)
+               {
+                       num_parsed = -1;
+                       if (exact && s [sPos] != '/')
+                               return false;
+
+                       if (_ParseTimeSeparator (s, sPos, dfi, exact, out num_parsed) ||
+                               Char.IsDigit (s [sPos]) || Char.IsLetter (s [sPos]))
+                               return(false);
+
+                       num_parsed = 1;
+                       return true;
+               }
+
+               private static bool IsLetter (string s, int pos)
+               {
+                       return pos < s.Length && Char.IsLetter (s [pos]);
+               }
+
+               // To implement better DateTime.Parse we use two format strings one
+               // for Date and one for Time. This allows us to define two different
+               // arrays of formats for Time and Dates and to combine them more or less
+               // efficiently. When this mode is used flexibleTwoPartsParsing is true.
+               private static bool _DoParse (string s,
+                                             string firstPart,
+                                             string secondPart,
+                                             bool exact,
+                                             out DateTime result,
+                                             out DateTimeOffset dto,
+                                             DateTimeFormatInfo dfi,
+                                             DateTimeStyles style,
+                                             bool firstPartIsDate,
+                                             ref bool incompleteFormat,
+                                             ref bool longYear)
+               {
+                       bool useutc = false;
                        bool use_invariant = false;
                        bool sloppy_parsing = false;
+                       dto = new DateTimeOffset (0, TimeSpan.Zero);
+                       bool flexibleTwoPartsParsing = !exact && secondPart != null;
+                       incompleteFormat = false;
                        int valuePos = 0;
+                       string format = firstPart;
+                       bool afterTFormat = false;
+                       DateTimeFormatInfo invInfo = DateTimeFormatInfo.InvariantInfo;
                        if (format.Length == 1)
-                               format = _GetStandardPattern (format [0], dfi, out useutc, out use_invariant);
-                       else if (!exact && CultureInfo.InvariantCulture.CompareInfo.IndexOf (format, "GMT", CompareOptions.Ordinal) >= 0)
-                               useutc = true;
+                               format = DateTimeUtils.GetStandardPattern (format [0], dfi, out useutc, out use_invariant);
+
+                       result = new DateTime (0);
+                       if (format == null)
+                               return false;
 
+                       if (s == null)
+                               return false;
+                               
                        if ((style & DateTimeStyles.AllowLeadingWhite) != 0) {
                                format = format.TrimStart (null);
 
@@ -921,25 +1200,92 @@ namespace System
                        }
 
                        if (use_invariant)
-                               dfi = DateTimeFormatInfo.InvariantInfo;
+                               dfi = invInfo;
 
                        if ((style & DateTimeStyles.AllowInnerWhite) != 0)
                                sloppy_parsing = true;
 
                        string chars = format;
                        int len = format.Length, pos = 0, num = 0;
+                       if (len == 0)
+                               return false;
 
                        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 isFirstPart = true;
 
-                       result = new DateTime (0);
-                       while (pos+num < len)
+                       for (; ; )
                        {
-                               if (s.Length == valuePos)
+                               if (valuePos == s.Length)
+                                       break;
+
+                               int num_parsed = 0;
+                               if (flexibleTwoPartsParsing && pos + num == 0)
+                               {
+                                       bool isLetter = IsLetter(s, valuePos);
+                                       if (isLetter) {
+                                               if (s [valuePos] == 'Z')
+                                                       num_parsed = 1;
+                                               else
+                                                       _ParseString (s, valuePos, 0, "GMT", out num_parsed);
+                                               if (num_parsed > 0 && !IsLetter (s, valuePos + num_parsed)) {
+                                                       valuePos += num_parsed;
+                                                       useutc = true;
+                                                       continue;
+                                               }
+                                       }
+                                       if (!afterTFormat && _ParseAmPm (s, valuePos, 0, dfi, exact, out num_parsed, ref ampm)) {
+                                               if (IsLetter (s, valuePos + num_parsed))
+                                                       ampm = -1;
+                                               else if (num_parsed > 0) {
+                                                       valuePos += num_parsed;
+                                                       continue;
+                                               }
+                                       }
+
+                                       if (!afterTFormat && dayofweek == -1 && isLetter) {
+                                               dayofweek = _ParseEnum (s, valuePos, dfi.RawDayNames, invInfo.RawDayNames, exact, out num_parsed);
+                                               if (dayofweek == -1)
+                                                       dayofweek = _ParseEnum (s, valuePos, dfi.RawAbbreviatedDayNames, invInfo.RawAbbreviatedDayNames, exact, out num_parsed);
+                                               if (dayofweek != -1 && !IsLetter (s, valuePos + num_parsed)) {
+                                                       valuePos += num_parsed;
+                                                       continue;
+                                               }
+                                               else
+                                                       dayofweek = -1;
+                                       }
+
+                                       if (char.IsWhiteSpace (s [valuePos]) || s [valuePos] == ',') {
+                                               valuePos += 1;
+                                               continue;
+                                       }
+                                       num_parsed = 0;
+                               }
+
+                               if (pos + num >= len)
+                               {
+                                       if (flexibleTwoPartsParsing && num == 0) {
+                                               afterTFormat = isFirstPart && firstPart [firstPart.Length - 1] == 'T';
+                                               if (!isFirstPart && format == "")
+                                                       break;
+
+                                               pos = 0;
+                                               if (isFirstPart)
+                                                       format = secondPart;
+                                               else
+                                                       format = "";
+                                               chars = format;
+                                               len = chars.Length;
+                                               isFirstPart = false;
+                                               continue;
+                                       }
                                        break;
+                               }
+
+                               bool leading_zeros = true;
 
                                if (chars[pos] == '\'') {
                                        num = 1;
@@ -947,16 +1293,12 @@ namespace System
                                                if (chars[pos+num] == '\'')
                                                        break;
 
-                                               if (valuePos == s.Length)
+                                               if (valuePos == s.Length || s [valuePos] != chars [pos + num])
                                                        return false;
-                                               if (s [valuePos] != chars [pos + num])
-                                                       return false;
-                                               valuePos++;
 
+                                               valuePos++;
                                                num++;
                                        }
-                                       if (pos+num > len)
-                                               return false;
 
                                        pos += num + 1;
                                        num = 0;
@@ -967,16 +1309,12 @@ namespace System
                                                if (chars[pos+num] == '"')
                                                        break;
 
-                                               if (valuePos == s.Length)
+                                               if (valuePos == s.Length || s [valuePos] != chars[pos+num])
                                                        return false;
-                                               if (s [valuePos] != chars[pos+num])
-                                                       return false;
-                                               valuePos++;
 
+                                               valuePos++;
                                                num++;
                                        }
-                                       if (pos+num > len)
-                                               return false;
 
                                        pos += num + 1;
                                        num = 0;
@@ -986,17 +1324,17 @@ namespace System
                                        num = 0;
                                        if (pos >= len)
                                                return false;
-
                                        if (s [valuePos] != chars [pos])
                                                return false;
+
                                        valuePos++;
                                        pos++;
                                        continue;
                                } else if (chars[pos] == '%') {
                                        pos++;
                                        continue;
-                               } else if (Char.IsWhiteSpace (s [valuePos]) ||
-                                       s [valuePos] == ',' && Char.IsWhiteSpace (chars [pos])) {
+                               } else if (char.IsWhiteSpace (s [valuePos]) ||
+                                       s [valuePos] == ',' && (!exact && chars [pos] == '/' || Char.IsWhiteSpace (chars [pos]))) {
                                        valuePos++;
                                        num = 0;
                                        if (exact && (style & DateTimeStyles.AllowInnerWhite) == 0) {
@@ -1022,6 +1360,10 @@ namespace System
                                                        break;
                                        }
                                        pos = ws;
+                                       // A whitespace may match a '/' in the pattern.
+                                       if (!exact && pos < chars.Length && chars[pos] == '/')
+                                               if (!_ParseDateSeparator (s, valuePos, dfi, exact, out num_parsed))
+                                                       pos++;
                                        continue;
                                }
 
@@ -1030,51 +1372,54 @@ namespace System
                                        continue;
                                }
 
-
-                               int num_parsed = 0;
-
                                switch (chars[pos])
                                {
                                case 'd':
-                                       if (day != -1)
+                                       if (num < 2 && day != -1 || num >= 2 && dayofweek != -1)
                                                return false;
                                        if (num == 0)
-                                               day = _ParseNumber (s, valuePos,0, 2, false, sloppy_parsing, out num_parsed);
+                                               day = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
                                        else if (num == 1)
-                                               day = _ParseNumber (s, valuePos,0, 2, true, sloppy_parsing, out num_parsed);
+                                               day = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
                                        else if (num == 2)
-                                               dayofweek = _ParseEnum (s, valuePos, dfi.AbbreviatedDayNames, out num_parsed);
+                                               dayofweek = _ParseEnum (s, valuePos, dfi.RawAbbreviatedDayNames, invInfo.RawAbbreviatedDayNames, exact, out num_parsed);
                                        else
-                                       {
-                                               dayofweek = _ParseEnum (s, valuePos, dfi.DayNames, out num_parsed);
-                                               num = 3;
-                                       }
+                                               dayofweek = _ParseEnum (s, valuePos, dfi.RawDayNames, invInfo.RawDayNames, exact, out num_parsed);
                                        break;
                                case 'M':
                                        if (month != -1)
                                                return false;
+
+                                       if (flexibleTwoPartsParsing) {
+                                               num_parsed = -1;
+                                               if (num == 0 || num == 3)
+                                                       month = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
+                                               if (num > 1 && num_parsed == -1)
+                                                       month = _ParseEnum (s, valuePos, dfi.RawMonthNames, invInfo.RawMonthNames, exact, out num_parsed) + 1;
+                                               if (num > 1 && num_parsed == -1)
+                                                       month = _ParseEnum (s, valuePos, dfi.RawAbbreviatedMonthNames, invInfo.RawAbbreviatedMonthNames, exact, out num_parsed) + 1;
+                                               break;
+                                       }
+
                                        if (num == 0)
-                                               month = _ParseNumber (s, valuePos, 0, 2, false, sloppy_parsing, out num_parsed);
+                                               month = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
                                        else if (num == 1)
-                                               month = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
+                                               month = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
                                        else if (num == 2)
-                                               month = _ParseEnum (s, valuePos, dfi.AbbreviatedMonthNames , out num_parsed) + 1;
+                                               month = _ParseEnum (s, valuePos, dfi.RawAbbreviatedMonthNames, invInfo.RawAbbreviatedMonthNames, exact, out num_parsed) + 1;
                                        else
-                                       {
-                                               month = _ParseEnum (s, valuePos, dfi.MonthNames, out num_parsed) + 1;
-                                               num = 3;
-                                       }
+                                               month = _ParseEnum (s, valuePos, dfi.RawMonthNames, invInfo.RawMonthNames, exact, out num_parsed) + 1;
                                        break;
                                case 'y':
                                        if (year != -1)
                                                return false;
 
                                        if (num == 0) {
-                                               year = _ParseNumber (s, valuePos,0, 2, false, sloppy_parsing, out num_parsed);
+                                               year = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
                                        } else if (num < 3) {
-                                               year = _ParseNumber (s, valuePos,0, 2, true, sloppy_parsing, out num_parsed);
+                                               year = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
                                        } else {
-                                               year = _ParseNumber (s, valuePos,4, 4, false, sloppy_parsing, out num_parsed);
+                                               year = _ParseNumber (s, valuePos, exact ? 4 : 3, 4, false, sloppy_parsing, out num_parsed);
                                                if ((year >= 1000) && (num_parsed == 4) && (!longYear) && (s.Length > 4 + valuePos)) {
                                                        int np = 0;
                                                        int ly = _ParseNumber (s, valuePos, 5, 5, false, sloppy_parsing, out np);
@@ -1091,12 +1436,9 @@ namespace System
                                        if (hour != -1)
                                                return false;
                                        if (num == 0)
-                                               hour = _ParseNumber (s, valuePos,0, 2, false, sloppy_parsing, out num_parsed);
+                                               hour = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
                                        else
-                                       {
-                                               hour = _ParseNumber (s, valuePos,0, 2, true, sloppy_parsing, out num_parsed);
-                                               num = 1;
-                                       }
+                                               hour = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
 
                                        if (hour > 12)
                                                return false;
@@ -1105,15 +1447,13 @@ namespace System
 
                                        break;
                                case 'H':
-                                       if ((hour != -1) || (ampm >= 0))
+                                       if (hour != -1 || !flexibleTwoPartsParsing && ampm >= 0)
                                                return false;
                                        if (num == 0)
-                                               hour = _ParseNumber (s, valuePos,0, 2, false, sloppy_parsing, out num_parsed);
+                                               hour = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
                                        else
-                                       {
-                                               hour = _ParseNumber (s, valuePos,0, 2, true, sloppy_parsing, out num_parsed);
-                                               num = 1;
-                                       }
+                                               hour = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
+
                                        if (hour >= 24)
                                                return false;
 
@@ -1123,12 +1463,10 @@ namespace System
                                        if (minute != -1)
                                                return false;
                                        if (num == 0)
-                                               minute = _ParseNumber (s, valuePos, 0, 2, false, sloppy_parsing, out num_parsed);
+                                               minute = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
                                        else
-                                       {
-                                               minute = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
-                                               num = 1;
-                                       }
+                                               minute = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
+
                                        if (minute >= 60)
                                                return false;
 
@@ -1137,53 +1475,33 @@ namespace System
                                        if (second != -1)
                                                return false;
                                        if (num == 0)
-                                               second = _ParseNumber (s, valuePos, 0, 2, false, sloppy_parsing, out num_parsed);
+                                               second = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
                                        else
-                                       {
-                                               second = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
-                                               num = 1;
-                                       }
+                                               second = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
+
                                        if (second >= 60)
                                                return false;
 
                                        break;
+                               case 'F':
+                                       leading_zeros = false;
+                                       goto case 'f';
                                case 'f':
-                                       if (fractionalSeconds != -1)
+                                       if (num > 6 || fractionalSeconds != -1)
                                                return false;
-                                       num = Math.Min (num, 6);
-                                       double decimalNumber = (double) _ParseNumber (s, valuePos, 0, num+1, true, sloppy_parsing, out num_parsed);
+                                       double decimalNumber = (double) _ParseNumber (s, valuePos, 0, num+1, leading_zeros, sloppy_parsing, out num_parsed);
                                        if (num_parsed == -1)
                                                return false;
-
-                                       else
-                                               fractionalSeconds = decimalNumber / Math.Pow(10.0, num_parsed);
+                                       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
+                                       if (!_ParseAmPm (s, valuePos, num > 0 ? 0 : 1, dfi, exact, out num_parsed, ref ampm))
                                                        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] == '-')
@@ -1191,25 +1509,61 @@ namespace System
                                        else
                                                return false;
                                        valuePos++;
+
                                        if (num == 0)
-                                               tzoffset = _ParseNumber (s, valuePos, 0, 2, false, sloppy_parsing, out num_parsed);
+                                               tzoffset = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
                                        else if (num == 1)
-                                               tzoffset = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
-                                       else
-                                       {
-                                               tzoffset = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
+                                               tzoffset = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
+                                       else {
+                                               tzoffset = _ParseNumber (s, valuePos, 1, 2, true, /*sloppy_parsing*/true, out num_parsed);
+                                               valuePos += num_parsed;
                                                if (num_parsed < 0)
                                                        return false;
+
+                                               num_parsed = 0;
+                                               if (valuePos < s.Length && Char.IsDigit (s [valuePos]) ||
+                                                       _ParseTimeSeparator (s, valuePos, dfi, exact, out num_parsed)) {
+                                                       valuePos += num_parsed;
+                                                       tzoffmin = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
+                                                       if (num_parsed < 0)
+                                                               return false;
+                                               }
+                                               else if (!flexibleTwoPartsParsing)
+                                                       return false;
+                                               else
+                                                       num_parsed = 0;
+                                       }
+                                       break;
+                               case 'K':
+                                       if (s [valuePos] == 'Z') {
+                                               valuePos++;
+                                               useutc = true;                                          
+                                       }
+                                       else if (s [valuePos] == '+' || s [valuePos] == '-') {
+                                               if (tzsign != -1)
+                                                       return false;
+                                               if (s [valuePos] == '+')
+                                                       tzsign = 0;
+                                               else if (s [valuePos] == '-')
+                                                       tzsign = 1;
+                                               valuePos++;
+
+                                               // zzz
+                                               tzoffset = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
                                                valuePos += num_parsed;
+                                               if (num_parsed < 0)
+                                                       return false;
+
                                                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, 0, 2, true, sloppy_parsing, out num_parsed);
+                                               num = 2;
                                                if (num_parsed < 0)
                                                        return false;
-                                               num = 2;
                                        }
                                        break;
 
@@ -1227,50 +1581,37 @@ namespace System
                                        num_parsed = 1;
                                        useutc = true;
                                        break;
+                               case 'G':
+                                       if (s [valuePos] != 'G')
+                                               return false;
 
+                                       if ((pos + 2 < len) && (valuePos + 2 < s.Length) &&
+                                               (chars [pos + 1] == 'M') && (s[valuePos + 1] == 'M') &&
+                                               (chars [pos + 2] == 'T') && (s[valuePos + 2] == 'T'))
+                                       {
+                                               useutc = true;
+                                               num = 2;
+                                               num_parsed = 3;
+                                       }
+                                       else {
+                                               num = 0;
+                                               num_parsed = 1;
+                                       }
+                                       break;
                                case ':':
-                                       if (!_ParseString (s, valuePos, 0, dfi.TimeSeparator, out num_parsed))
+                                       if (!_ParseTimeSeparator (s, valuePos, dfi, exact, 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] != '/')
+                                       if (!_ParseDateSeparator (s, valuePos, dfi, exact, out num_parsed))
                                                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]))
+                                       if (s [valuePos] != chars [pos])
                                                        return false;
-                                       }
+
                                        num = 0;
                                        num_parsed = 1;
                                        break;
@@ -1281,15 +1622,15 @@ namespace System
 
                                valuePos += num_parsed;
 
-                               if (!exact) {
+                               if (!exact && !flexibleTwoPartsParsing) {
                                        switch (chars [pos]) {
                                        case 'm':
                                        case 's':
+                                       case 'F':
                                        case 'f':
                                        case 'z':
-                                               if (s.Length > valuePos && s [valuePos] == 'Z'
-                                                   && (pos + 1 == chars.Length
-                                                   || chars [pos + 1] != 'Z')) {
+                                               if (s.Length > valuePos && s [valuePos] == 'Z' &&
+                                                       (pos + 1 == chars.Length || chars [pos + 1] != 'Z')) {
                                                        useutc = true;
                                                        valuePos++;
                                                }
@@ -1301,15 +1642,29 @@ namespace System
                                num = 0;
                        }
 
-                       // possible empty value. Regarded as no match.
-                       if (pos == 0)
-                               return false;
+                       if (pos + 1 < len && chars [pos] == '.' && chars [pos + 1] == 'F') {
+                               pos++;
+                               while (pos < len && chars [pos] == 'F') // '.FFF....' can be mapped to nothing. See bug #444103
+                                       pos++;
+                       }
+                       while (pos < len && chars [pos] == 'K') // 'K' can be mapped to nothing
+                               pos++;
 
                        if (pos < len)
                                return false;
 
-                       if (s.Length != valuePos) // extraneous tail.
+                       if (s.Length > valuePos) // extraneous tail.
+                       {
+                               if (valuePos == 0)
+                                       return false;
+
+                               if (Char.IsDigit (s [valuePos]) && Char.IsDigit (s [valuePos - 1]))
+                                       return false;
+                               if (Char.IsLetter (s [valuePos]) && Char.IsLetter (s [valuePos - 1]))
+                                       return false;
+                               incompleteFormat = true;
                                return false;
+                       }
 
                        if (hour == -1)
                                hour = 0;
@@ -1328,13 +1683,12 @@ namespace System
                                        month = 1;
                                        year = 1;
                                } else {
-                                       day = Today.Day;
-                                       month = Today.Month;
-                                       year = Today.Year;
+                                       day = DateTime.Today.Day;
+                                       month = DateTime.Today.Month;
+                                       year = DateTime.Today.Year;
                                }
                        }
 
-
                        if (day == -1)
                                day = 1;
                        if (month == -1)
@@ -1343,168 +1697,219 @@ namespace System
                                if ((style & DateTimeStyles.NoCurrentDateDefault) != 0)
                                        year = 1;
                                else
-                                       year = Today.Year;
+                                       year = DateTime.Today.Year;
                        }
 
-                       if (ampm == 1)
+                       if (ampm == 0 && hour == 12)
+                               hour = 0;
+
+                       if (ampm == 1 && (!flexibleTwoPartsParsing || hour < 12))
                                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 )
+                       if (year < 1 || year > 9999 || 
+                               month < 1 || month >12  ||
+                               day < 1 || day > DateTime.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);
 
-                       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 (dayofweek != -1 && dayofweek != (int) result.DayOfWeek)
+                               return false;
 
-                       if (useutc) {
-                               if ((style & DateTimeStyles.AdjustToUniversal) != 0)
-                                       use_localtime = false;
-                               utcoffset = new TimeSpan (0, 0, 0);
-                       } else if (tzsign == -1) {
-                               TimeZone tz = TimeZone.CurrentTimeZone;
-                               utcoffset = tz.GetUtcOffset (result);
+                       if (tzsign == -1) {
+                               if (result != DateTime.MinValue) {
+                                       try {
+                                               dto = new DateTimeOffset (result);
+                                       } catch { } // We handle this error in DateTimeOffset.Parse
+                               }
                        } 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);
+                               if (tzsign == 1) {
+                                       tzoffset = -tzoffset;
+                                       tzoffmin = -tzoffmin;
+                               }
+                               try {
+                                       dto = new DateTimeOffset (result, new TimeSpan (tzoffset, tzoffmin, 0));
+                               } catch {} // We handle this error in DateTimeOffset.Parse
+                       }
+                       bool adjustToUniversal = (style & DateTimeStyles.AdjustToUniversal) != 0;
+                       
+                       if (tzsign != -1) {
+                               long newticks = (result.ticks - dto.Offset).Ticks;
+                               if (newticks < 0)
+                                       newticks += TimeSpan.TicksPerDay;
+                               result = new DateTime (false, new TimeSpan (newticks));
+                               result.kind = DateTimeKind.Utc;
+                               if ((style & DateTimeStyles.RoundtripKind) != 0)
+                                       result = result.ToLocalTime ();
+                       }
+                       else if (useutc || ((style & DateTimeStyles.AssumeUniversal) != 0))
+                               result.kind = DateTimeKind.Utc;
+                       else if ((style & DateTimeStyles.AssumeLocal) != 0)
+                               result.kind = DateTimeKind.Local;                                               
+
+                       bool adjustToLocal = !adjustToUniversal && (style & DateTimeStyles.RoundtripKind) == 0;
+                       if (result.kind != DateTimeKind.Unspecified)
+                       {                               
+                               if (adjustToUniversal)
+                                       result = result.ToUniversalTime ();
+                               else if (adjustToLocal)
+                                       result = result.ToLocalTime ();
                        }
-
-                       long newticks = (result.ticks - utcoffset).Ticks;
-
-                       result = new DateTime (false, new TimeSpan (newticks));
-                       if (use_localtime)
-                               result = result.ToLocalTime ();
-
                        return true;
                }
 
-
                public static DateTime ParseExact (string s, string format,
-                                                  IFormatProvider fp, DateTimeStyles style)
+                                                  IFormatProvider provider, DateTimeStyles style)
                {
-                       string[] formats;
+                       if (format == null)
+                               throw new ArgumentNullException ("format");
 
-                       formats = new string [1];
+                       string [] formats = new string [1];
                        formats[0] = format;
 
-                       return ParseExact (s, formats, fp, style);
+                       return ParseExact (s, formats, provider, style);
                }
 
                public static DateTime ParseExact (string s, string[] formats,
-                                                  IFormatProvider fp,
+                                                  IFormatProvider provider,
                                                   DateTimeStyles style)
                {
-                       DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (fp);
-
+                       DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
+                       CheckStyle (style);
                        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"));
+                               throw new ArgumentNullException ("s");
+                       if (formats == null)
+                               throw new ArgumentNullException ("formats");
+                       if (formats.Length == 0)
+                               throw new FormatException ("Format specifier was invalid.");
 
                        DateTime result;
                        bool longYear = false;
-                       if (!ParseExact (s, formats, dfi, style, out result, true, ref longYear))
-                               throw new FormatException ();
+                       Exception e = null;
+                       if (!ParseExact (s, formats, dfi, style, out result, true, ref longYear, true, ref e))
+                               throw e;
                        return result;
+               }               
+
+               private static void CheckStyle (DateTimeStyles style)
+               {
+                       if ( (style & DateTimeStyles.RoundtripKind) != 0)
+                       {
+                               if ((style & DateTimeStyles.AdjustToUniversal) != 0 || (style & DateTimeStyles.AssumeLocal) != 0 ||
+                                        (style & DateTimeStyles.AssumeUniversal) != 0)
+                                       throw new ArgumentException ("The DateTimeStyles value RoundtripKind cannot be used with the values AssumeLocal, Asersal or AdjustToUniversal.", "style");
+                       }
+                       if ((style & DateTimeStyles.AssumeUniversal) != 0 && (style & DateTimeStyles.AssumeLocal) != 0)                 
+                               throw new ArgumentException ("The DateTimeStyles values AssumeLocal and AssumeUniversal cannot be used together.", "style");
                }
 
-#if NET_2_0
                public static bool TryParse (string s, out DateTime result)
                {
-                       try {
-                               result = Parse (s);
-                       } catch {
-                               result = MinValue;
-                               return false;
+                       if (s != null){
+                               try {
+                                       Exception exception = null;
+                                       DateTimeOffset dto;
+
+                                       return CoreParse (s, null, DateTimeStyles.AllowWhiteSpaces, out result, out dto, false, ref exception);
+                               } catch { }
                        }
-                       return true;
+                       result = MinValue;
+                       return false;
                }
                
                public static bool TryParse (string s, IFormatProvider provider, DateTimeStyles styles, out DateTime result)
                {
-                       try {
-                               result = Parse (s, provider, styles);
-                       } catch {
-                               result = MinValue;
-                               return false;
-                       }
-                       return true;
+                       if (s != null){
+                               try {
+                                       Exception exception = null;
+                                       DateTimeOffset dto;
+                                       
+                                       return CoreParse (s, provider, styles, out result, out dto, false, ref exception);
+                               } catch {}
+                       } 
+                       result = MinValue;
+                       return false;
                }
                
                public static bool TryParseExact (string s, string format,
-                                                 IFormatProvider fp,
+                                                 IFormatProvider provider,
                                                  DateTimeStyles style,
                                                  out DateTime result)
                {
                        string[] formats;
-
                        formats = new string [1];
                        formats[0] = format;
 
-                       return TryParseExact (s, formats, fp, style, out result);
+                       return TryParseExact (s, formats, provider, style, out result);
                }
 
                public static bool TryParseExact (string s, string[] formats,
-                                                 IFormatProvider fp,
+                                                 IFormatProvider provider,
                                                  DateTimeStyles style,
                                                  out DateTime result)
                {
-                       DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (fp);
+                       try {
+                               DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
 
-                       bool longYear = false;
-                       return ParseExact (s, formats, dfi, style, out result, true, ref longYear);
+                               bool longYear = false;
+                               Exception e = null;
+                               return ParseExact (s, formats, dfi, style, out result, true, ref longYear, false, ref e);
+                       } catch {
+                               result = MinValue;
+                               return false;
+                       }
                }
-#endif
 
                private static bool ParseExact (string s, string [] formats,
-                       DateTimeFormatInfo dfi, DateTimeStyles style, out DateTime ret,
-                       bool exact, ref bool longYear)
+                                               DateTimeFormatInfo dfi, DateTimeStyles style, out DateTime ret,
+                                               bool exact, ref bool longYear,
+                                               bool setExceptionOnError, ref Exception exception)
                {
                        int i;
+                       bool incompleteFormat = false;
                        for (i = 0; i < formats.Length; i++)
                        {
                                DateTime result;
+                               string format = formats[i];
+                               if (format == null || format == String.Empty)
+                                       break;
 
-                               if (_DoParse (s, formats[i], exact, out result, dfi, style, ref longYear)) {
+                               DateTimeOffset dto;
+                               if (_DoParse (s, formats[i], null, exact, out result, out dto, dfi, style, false, ref incompleteFormat, ref longYear)) {
                                        ret = result;
                                        return true;
                                }
                        }
+
+                       if (setExceptionOnError)
+                               exception = new FormatException ("Invalid format string");
                        ret = DateTime.MinValue;
                        return false;
                }
                
-               public TimeSpan Subtract(DateTime dt)
-               {   
-                       return new TimeSpan(ticks.Ticks) - dt.ticks;
+               public TimeSpan Subtract (DateTime value)
+               {
+                       return new TimeSpan (ticks.Ticks) - value.ticks;
                }
 
-               public DateTime Subtract(TimeSpan ts)
+               public DateTime Subtract(TimeSpan value)
                {
                        TimeSpan newticks;
 
-                       newticks = (new TimeSpan (ticks.Ticks)) - ts;
-                       return new DateTime(true,newticks);
+                       newticks = (new TimeSpan (ticks.Ticks)) - value;
+                       DateTime ret = new DateTime (true,newticks);
+                       ret.kind = kind;
+                       return ret;
                }
 
                public long ToFileTime()
@@ -1518,7 +1923,6 @@ namespace System
                        return(universalTime.Ticks - w32file_epoch);
                }
 
-#if NET_1_1
                public long ToFileTimeUtc()
                {
                        if (Ticks < w32file_epoch) {
@@ -1527,7 +1931,6 @@ namespace System
                        
                        return (Ticks - w32file_epoch);
                }
-#endif
 
                public string ToLongDateString()
                {
@@ -1580,349 +1983,39 @@ namespace System
                        return ToString ("G", null);
                }
 
-               public string ToString (IFormatProvider fp)
+               public string ToString (IFormatProvider provider)
                {
-                       return ToString (null, fp);
+                       return ToString (null, provider);
                }
 
                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)
-
+               public string ToString (string format, IFormatProvider provider)
                {
-                       DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance(fp);
+                       DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
 
-                       if (format == null)
+                       if (format == null || format == String.Empty)
                                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);
+                               format = DateTimeUtils.GetStandardPattern (fchar, dfi, out useutc, out use_invariant);
+                               if (fchar == 'U')
+                                       return DateTimeUtils.ToString (ToUniversalTime (), format, dfi);
+//                                     return ToUniversalTime()._ToString (format, dfi);
+
+                               if (format == null)
+                                       throw new FormatException ("format is not one of the format specifier characters defined for DateTimeFormatInfo");
                        }
 
                        // Don't convert UTC value. It just adds 'Z' for 
                        // 'u' format, for the same ticks.
-                       return this._ToString (format, dfi);
+                       return DateTimeUtils.ToString (this, format, dfi);
                }
 
                public DateTime ToLocalTime ()
@@ -1939,7 +2032,9 @@ namespace System
 
                public static DateTime operator +(DateTime d, TimeSpan t)
                {
-                       return new DateTime (true, d.ticks + t);
+                       DateTime ret = new DateTime (true, d.ticks + t);
+                       ret.kind = d.kind;
+                       return ret;
                }
 
                public static bool operator ==(DateTime d1, DateTime d2)
@@ -1979,7 +2074,9 @@ namespace System
 
                public static DateTime operator -(DateTime d,TimeSpan t)
                {
-                       return new DateTime (true, d.ticks - t);
+                       DateTime ret = new DateTime (true, d.ticks - t);
+                       ret.kind = d.kind;
+                       return ret;
                }
 
                bool IConvertible.ToBoolean(IFormatProvider provider)
@@ -2038,16 +2135,16 @@ namespace System
                        throw new InvalidCastException();
                }
 
-               object IConvertible.ToType (Type conversionType, IFormatProvider provider)
+               object IConvertible.ToType (Type targetType, IFormatProvider provider)
                {
-                       if (conversionType == null)
-                               throw new ArgumentNullException ("conversionType");
+                       if (targetType == null)
+                               throw new ArgumentNullException ("targetType");
 
-                       if (conversionType == typeof (DateTime))
+                       if (targetType == typeof (DateTime))
                                return this;
-                       else if (conversionType == typeof (String))
+                       else if (targetType == typeof (String))
                                return this.ToString (provider);
-                       else if (conversionType == typeof (Object))
+                       else if (targetType == typeof (Object))
                                return this;
                        else
                                throw new InvalidCastException();
@@ -2057,7 +2154,7 @@ namespace System
                {
                        throw new InvalidCastException();
                }
-               
+
                UInt32 IConvertible.ToUInt32(IFormatProvider provider)
                {
                        throw new InvalidCastException();
@@ -2067,5 +2164,15 @@ namespace System
                {
                        throw new InvalidCastException();
                }
+
+               void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
+               {
+                       long t = ticks.Ticks;
+                       info.AddValue ("ticks", t);
+
+                       // This is the new .NET format, encodes the kind on the top bits
+                       info.AddValue ("dateData", t | (((uint)kind) << 62));
+               }
+               
        }
 }