New tests.
[mono.git] / mcs / class / corlib / System / DateTime.cs
index 535c601198eb215a53222cc48430e2fe6209356e..94c8a73a63577e7ab524aa04daeba40c501d7734 100644 (file)
@@ -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;
@@ -88,6 +92,7 @@ namespace System
                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",
@@ -109,13 +114,9 @@ namespace System
                        "M/yyyy/dT",
                        "yyyy'\u5E74'M'\u6708'd'\u65E5",
 
-#if NET_2_0
+
                        "yyyy/d/MMMM",
                        "yyyy/MMM/d",
-#else
-                       "yyyy/MMMM/d",
-                       "yyyy/d/MMM",
-#endif
                        "d/MMMM/yyyy",
                        "MMM/d/yyyy",
                        "d/yyyy/MMMM",
@@ -190,11 +191,7 @@ namespace System
                };
                private static readonly string[] DayMonthShortFormats = new string [] {
                        "d/MMMM",
-#if NET_2_0
                        "MMM/yy",
-#else // In .Net 1.0 Feb 03 is always Feb 3rd (and not Feb 2003)
-                       "MMM/d",
-#endif
                        "yyyy/MMMM",
                };
 
@@ -278,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)
@@ -303,9 +298,7 @@ namespace System
 
                        ticks = new TimeSpan (AbsoluteDays(year,month,day), hour, minute, second, millisecond);
 
-#if NET_2_0
                        kind = DateTimeKind.Unspecified;
-#endif
                }
 
                public DateTime (int year, int month, int day, Calendar calendar)
@@ -323,9 +316,7 @@ namespace System
                        if (calendar == null)
                                throw new ArgumentNullException ("calendar");
                        ticks = calendar.ToDateTime (year, month, day, hour, minute, second, millisecond).ticks;
-#if NET_2_0
                        kind = DateTimeKind.Unspecified;
-#endif
                }
 
                internal DateTime (bool check, TimeSpan value)
@@ -335,12 +326,9 @@ namespace System
 
                        ticks = value;
 
-#if NET_2_0
                        kind = DateTimeKind.Unspecified;
-#endif
                }
 
-#if NET_2_0
                public DateTime (long ticks, DateTimeKind kind) : this (ticks)
                {
                        CheckDateTimeKind (kind);
@@ -366,9 +354,27 @@ 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 
@@ -376,9 +382,7 @@ namespace System
                        get     
                        { 
                                DateTime ret = new DateTime (Year, Month, Day);
-#if NET_2_0
                                ret.kind = kind;
-#endif
                                return ret;
                        }
                }
@@ -456,6 +460,9 @@ namespace System
                        }
                }
                
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               internal static extern long GetTimeMonotonic ();
+
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                internal static extern long GetNow ();
 
@@ -483,9 +490,7 @@ namespace System
 
                                // This is boxed, so we avoid locking.
                                DateTime ret = dt + (TimeSpan) to_local_time_span_object;
-#if NET_2_0
                                ret.kind = DateTimeKind.Local;
-#endif
                                return ret;
                        }
                }
@@ -503,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;
                        }
                }
@@ -513,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
                        }
                }
 
@@ -529,54 +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)
                {
-                       DateTime ret = AddTicks (ts.Ticks);
-#if NET_2_0
+                       DateTime ret = AddTicks (value.Ticks);
                        ret.kind = kind;
-#endif
                        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();
                        }
-                       DateTime ret = new DateTime (t + ticks.Ticks);
-#if NET_2_0
+                       DateTime ret = new DateTime (value + ticks.Ticks);
                        ret.kind = kind;
-#endif
                        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);
                }
@@ -593,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)
@@ -622,20 +615,18 @@ namespace System
                                day = maxday;
 
                        temp = new DateTime (year, month, day);
-#if NET_2_0
                        temp.kind = kind;
-#endif
                        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)
@@ -648,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)
@@ -707,19 +697,6 @@ namespace System
                        return new DateTime (value.Ticks, kind);
                }
 
-#else
-
-               internal long ToBinary ()
-               {
-                       return Ticks;
-               }
-
-               internal static DateTime FromBinary (long dateData)
-               {
-                       return new DateTime (dateData & 0x3fffffffffffffff);
-               }
-#endif
-
                public static int DaysInMonth (int year, int month)
                {
                        int[] days ;
@@ -734,12 +711,12 @@ namespace System
                        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 )
@@ -755,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)
@@ -763,7 +739,6 @@ namespace System
 
                        return new DateTime (w32file_epoch + fileTime);
                }
-#endif
 
                public static DateTime FromOADate (double d)
                {
@@ -846,12 +821,10 @@ namespace System
                        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 ()
                {
@@ -875,124 +848,154 @@ 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);
                }
 
-               public static DateTime Parse (string s, IFormatProvider fp, DateTimeStyles styles)
+               public static DateTime Parse (string s, IFormatProvider provider, DateTimeStyles styles)
                {
-                       
-                       const string formatExceptionMessage = "String was not recognized as a valid DateTime.";
-#if !NET_2_0
-                       const string argumentYearRangeExceptionMessage = "Valid values are between 1 and 9999, inclusive.";
-#endif
-                       
                        if (s == null)
-                               throw new ArgumentNullException (Locale.GetText ("s is null"));
-                       if (fp == null)
-                               fp = CultureInfo.CurrentCulture;
-                       DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (fp);
+                               throw new ArgumentNullException ("s");
+
+                       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);
 
-                       bool longYear = false;
-                       DateTime result;
                        // Try first all the combinations of ParseAllDateFormats & ParseTimeFormats
-                       string[] allDateFormats = YearMonthDayFormats (dfi);
+                       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, dfi, styles, true, ref incompleteFormat, ref longYear))
-                                       return result;
+                               if (_DoParse (s, firstPart, "", false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
+                                       return true;
+
                                if (!incompleteFormat)
                                        continue;
 
                                for (int j = 0; j < ParseTimeFormats.Length; j++) {
-                                       if (_DoParse (s, firstPart, ParseTimeFormats [j], false, out result, dfi, styles, true, ref incompleteFormat, ref longYear))
-                                               return result;
+                                       if (_DoParse (s, firstPart, ParseTimeFormats [j], false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
+                                               return true;
                                }
                        }
-                       string[] monthDayFormats = IsDayBeforeMonth (dfi) ? DayMonthShortFormats : MonthDayShortFormats;
+
+                       //
+                       // 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, dfi, styles, true, ref incompleteFormat, ref longYear))
-                                       return result;
+                               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, dfi, styles, false, ref incompleteFormat, ref longYear))
-                                       return result;
+                               if (_DoParse (s, firstPart, "", false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
+                                       return true;
                                if (!incompleteFormat)
                                        continue;
 
                                for (int i = 0; i < monthDayFormats.Length; i++) {
-                                       if (_DoParse (s, firstPart, monthDayFormats [i], false, out result, dfi, styles, false, ref incompleteFormat, ref longYear))
-                                               return result;
+                                       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, dfi, styles, false, ref incompleteFormat, ref longYear))
-                                               return result;
+                                       if (_DoParse (s, firstPart, dateFormat, false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
+                                               return true;
                                }
                        }
 
                        // Try as a last resort all the patterns
-                       if (ParseExact (s, dfi.GetAllDateTimePatternsInternal (), dfi, styles, out result, false, ref longYear))
-                               return result;
-
-#if NET_2_0
-                       // .NET does not throw an ArgumentOutOfRangeException, but .NET 1.1 does.
-                       throw new FormatException (formatExceptionMessage);
-#else
-                       if (longYear) {
-                               throw new ArgumentOutOfRangeException ("year",
-                                       argumentYearRangeExceptionMessage);
-                       }
-
-                       throw new FormatException (formatExceptionMessage);
-#endif
-               }
+                       if (ParseExact (s, dfi.GetAllDateTimePatternsInternal (), dfi, styles, out result, false, ref longYear, setExceptionOnError, ref exception))
+                               return true;
 
-               public static DateTime ParseExact (string s, string format, IFormatProvider fp)
-               {
-                       return ParseExact (s, format, fp, DateTimeStyles.None);
+                       if (!setExceptionOnError)
+                               return false;
+                       
+                       // .NET 2.x does not throw an ArgumentOutOfRangeException, but .NET 1.1 does.
+                       exception = new FormatException (formatExceptionMessage);
+                       return false;
                }
 
-               private static bool IsDayBeforeMonth (DateTimeFormatInfo dfi)
+               public static DateTime ParseExact (string s, string format, IFormatProvider provider)
                {
-                       int dayIndex = dfi.MonthDayPattern.IndexOf('d');
-                       int monthIndex = dfi.MonthDayPattern.IndexOf('M');
-                       if (dayIndex == -1 || monthIndex == -1)
-                               throw new FormatException (Locale.GetText("Order of month and date is not defined by {0}", dfi.MonthDayPattern));
-
-                       return dayIndex < monthIndex;
+                       return ParseExact (s, format, provider, DateTimeStyles.None);
                }
 
-               private static string[] YearMonthDayFormats (DateTimeFormatInfo dfi)
+               private static string[] YearMonthDayFormats (DateTimeFormatInfo dfi, bool setExceptionOnError, ref Exception exc)
                {
                        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)
-                               throw new FormatException (Locale.GetText("Order of year, month and date is not defined by {0}", dfi.ShortDatePattern));
+                       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
+                               else {
                                        // The year cannot be between the date and the month
-                                       throw new FormatException (Locale.GetText("Order of date, year and month defined by {0} is not supported", dfi.ShortDatePattern));
+                                       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
+                       else {
                                // The year cannot be between the month and the date
-                               throw new FormatException (Locale.GetText("Order of month, year and date defined by {0} is not supported", dfi.ShortDatePattern));
+                               if (setExceptionOnError)
+                                       exc = new FormatException (Locale.GetText("Order of month, year and date defined by {0} is not supported", dfi.ShortDatePattern));
+                               return null;
+                       }
                }
 
                private static int _ParseNumber (string s, int valuePos,
@@ -1158,41 +1161,33 @@ namespace System
                                              string secondPart,
                                              bool exact,
                                              out DateTime result,
+                                             out DateTimeOffset dto,
                                              DateTimeFormatInfo dfi,
                                              DateTimeStyles style,
                                              bool firstPartIsDate,
                                              ref bool incompleteFormat,
                                              ref bool longYear)
                {
-#if NET_2_0
-                       DateTimeKind explicit_kind = DateTimeKind.Unspecified;
-#endif
-                       bool useutc = false, use_localtime = true;
+                       bool useutc = false;
                        bool use_invariant = false;
                        bool sloppy_parsing = false;
-                       bool afterTimePart = firstPartIsDate && secondPart == "";
+                       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) {
-                               if (format == "u")
-                                       use_localtime = false;
+                       if (format.Length == 1)
                                format = DateTimeUtils.GetStandardPattern (format [0], dfi, out useutc, out use_invariant);
-                       }
-                       else if (!exact && CultureInfo.InvariantCulture.CompareInfo.IndexOf (format, "GMT", CompareOptions.Ordinal) >= 0)
-                               useutc = true;
-#if NET_2_0
-                       if ((style & DateTimeStyles.AssumeUniversal) != 0)
-                               useutc = true;
-#endif
 
                        result = new DateTime (0);
                        if (format == null)
                                return false;
 
+                       if (s == null)
+                               return false;
+                               
                        if ((style & DateTimeStyles.AllowLeadingWhite) != 0) {
                                format = format.TrimStart (null);
 
@@ -1231,7 +1226,7 @@ namespace System
                                if (flexibleTwoPartsParsing && pos + num == 0)
                                {
                                        bool isLetter = IsLetter(s, valuePos);
-                                       if (afterTimePart && isLetter) {
+                                       if (isLetter) {
                                                if (s [valuePos] == 'Z')
                                                        num_parsed = 1;
                                                else
@@ -1285,8 +1280,6 @@ namespace System
                                                chars = format;
                                                len = chars.Length;
                                                isFirstPart = false;
-                                               if (!firstPartIsDate || format == "")
-                                                       afterTimePart = true;
                                                continue;
                                        }
                                        break;
@@ -1490,11 +1483,9 @@ namespace System
                                                return false;
 
                                        break;
-#if NET_2_0
                                case 'F':
                                        leading_zeros = false;
                                        goto case 'f';
-#endif
                                case 'f':
                                        if (num > 6 || fractionalSeconds != -1)
                                                return false;
@@ -1524,7 +1515,7 @@ namespace System
                                        else if (num == 1)
                                                tzoffset = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
                                        else {
-                                               tzoffset = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
+                                               tzoffset = _ParseNumber (s, valuePos, 1, 2, true, /*sloppy_parsing*/true, out num_parsed);
                                                valuePos += num_parsed;
                                                if (num_parsed < 0)
                                                        return false;
@@ -1543,12 +1534,10 @@ namespace System
                                                        num_parsed = 0;
                                        }
                                        break;
-#if NET_2_0
                                case 'K':
                                        if (s [valuePos] == 'Z') {
                                                valuePos++;
-                                               useutc = true;
-                                               explicit_kind = DateTimeKind.Utc;
+                                               useutc = true;                                          
                                        }
                                        else if (s [valuePos] == '+' || s [valuePos] == '-') {
                                                if (tzsign != -1)
@@ -1573,12 +1562,11 @@ namespace System
 
                                                tzoffmin = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
                                                num = 2;
-                                               explicit_kind = DateTimeKind.Local;
                                                if (num_parsed < 0)
                                                        return false;
                                        }
                                        break;
-#endif
+
                                // LAMESPEC: This should be part of UTCpattern
                                // string and thus should not be considered here.
                                //
@@ -1593,7 +1581,23 @@ 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 (!_ParseTimeSeparator (s, valuePos, dfi, exact, out num_parsed))
                                                return false;
@@ -1622,9 +1626,7 @@ namespace System
                                        switch (chars [pos]) {
                                        case 'm':
                                        case 's':
-#if NET_2_0
                                        case 'F':
-#endif
                                        case 'f':
                                        case 'z':
                                                if (s.Length > valuePos && s [valuePos] == 'Z' &&
@@ -1640,10 +1642,14 @@ namespace System
                                num = 0;
                        }
 
-#if NET_2_0
+                       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++;
-#endif
+
                        if (pos < len)
                                return false;
 
@@ -1716,50 +1722,54 @@ namespace System
                        if (dayofweek != -1 && dayofweek != (int) result.DayOfWeek)
                                return false;
 
-                       // If no timezone was specified, default to the local timezone.
-                       TimeSpan utcoffset;
-
-                       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)
+                               if (tzsign == 1) {
                                        tzoffset = -tzoffset;
-
-                               utcoffset = new TimeSpan (tzoffset, tzoffmin, 0);
+                                       tzoffmin = -tzoffmin;
+                               }
+                               try {
+                                       dto = new DateTimeOffset (result, new TimeSpan (tzoffset, tzoffmin, 0));
+                               } catch {} // We handle this error in DateTimeOffset.Parse
                        }
-
-                       long newticks = (result.ticks - utcoffset).Ticks;
-
-                       result = new DateTime (false, new TimeSpan (newticks));
-#if NET_2_0
-                       if (explicit_kind != DateTimeKind.Unspecified)
-                               result.kind = explicit_kind;
-                       else if (use_localtime)
-                               result = result.ToLocalTime ();
-                       else
+                       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;
-#else
-                       if (use_localtime)
-                               result = result.ToLocalTime ();
-#endif
-
+                               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 ();
+                       }
                        return true;
                }
 
                public static DateTime ParseExact (string s, string format,
-                                                  IFormatProvider fp, DateTimeStyles style)
+                                                  IFormatProvider provider, DateTimeStyles style)
                {
                        if (format == null)
                                throw new ArgumentNullException ("format");
@@ -1767,15 +1777,15 @@ namespace System
                        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 ("s");
                        if (formats == null)
@@ -1785,62 +1795,85 @@ namespace System
 
                        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;
@@ -1849,31 +1882,33 @@ namespace System
                                DateTime result;
                                string format = formats[i];
                                if (format == null || format == String.Empty)
-                                       throw new FormatException ("Invalid Format String");
+                                       break;
 
-                               if (_DoParse (s, formats[i], null, exact, out result, dfi, style, false, ref incompleteFormat, 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)
+               public TimeSpan Subtract (DateTime value)
                {
-                       return new TimeSpan(ticks.Ticks) - dt.ticks;
+                       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;
-                       DateTime ret = new DateTime(true,newticks);
-#if NET_2_0
+                       newticks = (new TimeSpan (ticks.Ticks)) - value;
+                       DateTime ret = new DateTime (true,newticks);
                        ret.kind = kind;
-#endif
                        return ret;
                }
 
@@ -1888,7 +1923,6 @@ namespace System
                        return(universalTime.Ticks - w32file_epoch);
                }
 
-#if NET_1_1
                public long ToFileTimeUtc()
                {
                        if (Ticks < w32file_epoch) {
@@ -1897,7 +1931,6 @@ namespace System
                        
                        return (Ticks - w32file_epoch);
                }
-#endif
 
                public string ToLongDateString()
                {
@@ -1950,9 +1983,9 @@ 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)
@@ -1960,9 +1993,9 @@ namespace System
                        return ToString (format, null);
                }
        
-               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 || format == String.Empty)
                                format = "G";
@@ -2000,9 +2033,7 @@ namespace System
                public static DateTime operator +(DateTime d, TimeSpan t)
                {
                        DateTime ret = new DateTime (true, d.ticks + t);
-#if NET_2_0
                        ret.kind = d.kind;
-#endif
                        return ret;
                }
 
@@ -2044,9 +2075,7 @@ namespace System
                public static DateTime operator -(DateTime d,TimeSpan t)
                {
                        DateTime ret = new DateTime (true, d.ticks - t);
-#if NET_2_0
                        ret.kind = d.kind;
-#endif
                        return ret;
                }
 
@@ -2106,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();
@@ -2125,7 +2154,7 @@ namespace System
                {
                        throw new InvalidCastException();
                }
-               
+
                UInt32 IConvertible.ToUInt32(IFormatProvider provider)
                {
                        throw new InvalidCastException();
@@ -2135,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));
+               }
+               
        }
 }