DateTime.FromFileTimeUtc should return a DateTime with DateTimeKind.Utc. Fixes #2936.
[mono.git] / mcs / class / corlib / System / DateTime.cs
index fee9254268083d7374dc568b68469d55953ad5ec..07b247897c1616259461078bb01dc897185c1e03 100644 (file)
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-using System.Collections;
+using System.Collections.Generic;
 using System.Globalization;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Text;
+using System.Runtime.Serialization;
 
 namespace System
 {
@@ -44,16 +45,18 @@ 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>
        {
-               private TimeSpan ticks;
-
-#if NET_2_0
-               DateTimeKind kind;
-#endif
+               //
+               // Encodes the DateTime in 64 bits, top two bits contain the DateTimeKind,
+               // the rest contains the 62 bit value for the ticks.   This reduces the
+               // memory usage from 16 to 8 bytes, see bug: 592221.   This also fixes the
+               // 622127 issue and simplifies the code in reflection.c to encode DateTimes
+               //
+               long encoded;
+               const long TicksMask = 0x3fffffffffffffff;
+               const long KindMask = unchecked ((long) 0xc000000000000000);
+               const int KindShift = 62;
 
                private const int dp400 = 146097;
                private const int dp100 = 36524;
@@ -78,16 +81,24 @@ namespace System
                private const double OAMinValue = -657435.0d;
                private const double OAMaxValue = 2958466.0d;
 
-               public static readonly DateTime MaxValue = new DateTime (false, new TimeSpan (MAX_VALUE_TICKS));
-               public static readonly DateTime MinValue = new DateTime (false, new TimeSpan (0));
+               public static readonly DateTime MaxValue = new DateTime (3155378975999999999);
+               public static readonly DateTime MinValue = new DateTime (0);
 
                // 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.fff zzz",
                        "H:m:s.fffffffzzz",
                        "H:m:s.fffffff",
+                       "H:m:s.ffffff",
+                       "H:m:s.fffff",
+                       "H:m:s.ffff",
+                       "H:m:s.fff",
+                       "H:m:s.ff",
+                       "H:m:s.f",
+                       "H:m:s tt zzz",
                        "H:m:szzz",
                        "H:m:s",
                        "H:mzzz",
@@ -109,13 +120,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",
@@ -180,6 +187,16 @@ namespace System
                        "d/yy/MMM",
                        "yy/d/MMM",
                };
+               
+               private static readonly string[] ParseGenericYearMonthDayFormats = new string [] {
+                       "yyyy/M/dT",
+                       "yyyy/M/d",
+                       "M/yyyy/dT",
+                       "M/yyyy/d",
+                       "yyyy'\u5E74'M'\u6708'd'\u65E5",
+                       "yyyy'-'M'-'dT",
+                       "yyyy'-'M'-'d",
+               };
 
                // Patterns influenced by the MonthDayPattern in DateTimeFormatInfo.
                // Note that these patterns cannot be followed by the time.
@@ -190,11 +207,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",
                };
 
@@ -227,7 +240,7 @@ namespace System
                        int M =1;
 
                        int[] days = daysmonth;
-                       int totaldays = this.ticks.Days;
+                       int totaldays = (int) ((encoded & TicksMask) / TimeSpan.TicksPerDay);
 
                        num400 = (totaldays / dp400);
                        totaldays -=  num400 * dp400;
@@ -263,6 +276,11 @@ namespace System
                        return totaldays +1; 
                }
 
+               static void InvalidTickValue (long ticks)
+               {
+                       string msg = Locale.GetText ("Value {0} is outside the valid range [0,{1}].", ticks, MAX_VALUE_TICKS);
+                       throw new ArgumentOutOfRangeException ("ticks", msg);
+               }
 
                // Constructors
                
@@ -272,15 +290,9 @@ namespace System
                /// 
                public DateTime (long ticks)
                {
-                       this.ticks = new TimeSpan (ticks);
-                       if (ticks < MinValue.Ticks || ticks > MaxValue.Ticks) {
-                               string msg = Locale.GetText ("Value {0} is outside the valid range [{1},{2}].", 
-                                       ticks, MinValue.Ticks, MaxValue.Ticks);
-                               throw new ArgumentOutOfRangeException ("ticks", msg);
-                       }
-#if NET_2_0
-                       kind = DateTimeKind.Unspecified;
-#endif
+                       if (ticks < 0 || ticks > MAX_VALUE_TICKS)
+                               InvalidTickValue (ticks);
+                       encoded = ticks;
                }
 
                public DateTime (int year, int month, int day)
@@ -290,22 +302,18 @@ namespace System
                        : this (year, month, day, hour, minute, second, 0)      {}
 
                public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond)
-                       {
-                       if ( year < 1 || year > 9999 || 
-                               month < 1 || month >12  ||
-                               day < 1 || day > DaysInMonth(year, month) ||
-                               hour < 0 || hour > 23 ||
-                               minute < 0 || minute > 59 ||
-                               second < 0 || second > 59 ||
-                               millisecond < 0 || millisecond > 999)
+               {
+                       if (year < 1 || year > 9999 || 
+                           month < 1 || month >12  ||
+                           day < 1 || day > DaysInMonth(year, month) ||
+                           hour < 0 || hour > 23 ||
+                           minute < 0 || minute > 59 ||
+                           second < 0 || second > 59 ||
+                           millisecond < 0 || millisecond > 999)
                                throw new ArgumentOutOfRangeException ("Parameters describe an " +
-                                                                       "unrepresentable DateTime.");
+                                                                      "unrepresentable DateTime.");
 
-                       ticks = new TimeSpan (AbsoluteDays(year,month,day), hour, minute, second, millisecond);
-
-#if NET_2_0
-                       kind = DateTimeKind.Unspecified;
-#endif
+                       encoded = new TimeSpan (AbsoluteDays (year,month,day), hour, minute, second, millisecond).Ticks;
                }
 
                public DateTime (int year, int month, int day, Calendar calendar)
@@ -322,137 +330,120 @@ 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
+                       encoded = calendar.ToDateTime (year, month, day, hour, minute, second, millisecond).encoded;
                }
 
-               internal DateTime (bool check, TimeSpan value)
+               public DateTime (long ticks, DateTimeKind kind) 
                {
-                       if (check && (value.Ticks < MinValue.Ticks || value.Ticks > MaxValue.Ticks))
-                               throw new ArgumentOutOfRangeException ();
-
-                       ticks = value;
-
-#if NET_2_0
-                       kind = DateTimeKind.Unspecified;
-#endif
-               }
+                       if (ticks < 0 || ticks > MAX_VALUE_TICKS)
+                               InvalidTickValue (ticks);
+                       if (kind < 0 || kind > DateTimeKind.Local)
+                               throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
 
-#if NET_2_0
-               public DateTime (long ticks, DateTimeKind kind) : this (ticks)
-               {
-                       CheckDateTimeKind (kind);
-                       this.kind = kind;
+                       encoded = ((long)kind << KindShift) | ticks;
                }
 
                public DateTime (int year, int month, int day, int hour, int minute, int second, DateTimeKind kind)
                        : this (year, month, day, hour, minute, second)
                {
-                       CheckDateTimeKind (kind);
-                       this.kind = kind;
+                       if (kind < 0 || kind > DateTimeKind.Local)
+                               throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
+                       encoded |= ((long)kind << KindShift);
                }
 
                public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind)
                        : this (year, month, day, hour, minute, second, millisecond)
                {
-                       CheckDateTimeKind (kind);
-                       this.kind = kind;
+                       if (kind < 0 || kind > DateTimeKind.Local)
+                               throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
+                       encoded |= ((long)kind << KindShift);
                }
 
                public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, DateTimeKind kind)
                        : this (year, month, day, hour, minute, second, millisecond, calendar)
                {
-                       CheckDateTimeKind (kind);
-                       this.kind = kind;
-               }                       
-#endif
+                       if (kind < 0 || kind > DateTimeKind.Local)
+                               throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
+                       encoded |= ((long)kind << KindShift);
+               }
 
+               //
+               // Not visible, but can be invoked during deserialization
+               //
+               DateTime (SerializationInfo info, StreamingContext context)
+               {
+                       if (info.HasKey ("dateData")){
+                               encoded = info.GetInt64 ("dateData");
+                       } else if (info.HasKey ("ticks")){
+                               encoded = info.GetInt64 ("ticks") & TicksMask;
+                       } else {
+                               encoded = 0;
+                       }
+               }
+               
+                             
                /* Properties  */
 
-               public DateTime Date 
-               {
-                       get     
-                       { 
+               public DateTime Date {
+                       get { 
                                DateTime ret = new DateTime (Year, Month, Day);
-#if NET_2_0
-                               ret.kind = kind;
-#endif
+                               ret.encoded |= encoded & KindMask;
                                return ret;
                        }
                }
 
-               public int Month 
-               {
-                       get     
-                       { 
-                               return FromTicks(Which.Month); 
+               public int Month {
+                       get { 
+                               return FromTicks (Which.Month); 
                        }
                }
 
-               public int Day
-               {
-                       get 
-                       { 
-                               return FromTicks(Which.Day); 
+               public int Day {
+                       get { 
+                               return FromTicks (Which.Day); 
                        }
                }
 
-               public DayOfWeek DayOfWeek 
-               {
-                       get 
-                       { 
-                               return ( (DayOfWeek) ((ticks.Days+1) % 7) ); 
+               public DayOfWeek DayOfWeek {
+                       get {
+                               return (DayOfWeek) ((((encoded & TicksMask)/TimeSpan.TicksPerDay)+1) % 7);
                        }
                }
 
-               public int DayOfYear 
-               {
-                       get 
-                       { 
-                               return FromTicks(Which.DayYear); 
+               public int DayOfYear {
+                       get { 
+                               return FromTicks (Which.DayYear); 
                        }
                }
 
-               public TimeSpan TimeOfDay 
-               {
-                       get     
-                       { 
-                               return new TimeSpan(ticks.Ticks % TimeSpan.TicksPerDay );
+               public TimeSpan TimeOfDay {
+                       get { 
+                               return new TimeSpan ((encoded & TicksMask) % TimeSpan.TicksPerDay);
                        }
                        
                }
 
-               public int Hour 
-               {
-                       get 
-                       { 
-                               return ticks.Hours;
+               public int Hour {
+                       get { 
+                               return (int) ((encoded & TicksMask) % TimeSpan.TicksPerDay / TimeSpan.TicksPerHour);
                        }
                }
 
-               public int Minute 
-               {
-                       get 
-                       { 
-                               return ticks.Minutes;
+               public int Minute {
+                       get { 
+                               return (int)  ((encoded & TicksMask) % TimeSpan.TicksPerHour / TimeSpan.TicksPerMinute);
                        }
                }
 
-               public int Second 
-               {
-                       get     
-                       { 
-                               return ticks.Seconds;
+               public int Second {
+                       get { 
+                               return (int) ((encoded & TicksMask) % TimeSpan.TicksPerMinute / TimeSpan.TicksPerSecond);
                        }
                }
 
-               public int Millisecond 
-               {
-                       get 
-                       { 
-                               return ticks.Milliseconds;
+               public int Millisecond {
+                       get { 
+                               return (int) ((encoded & TicksMask) % TimeSpan.TicksPerSecond / TimeSpan.TicksPerMillisecond);
                        }
                }
                
@@ -471,10 +462,8 @@ namespace System
                static object to_local_time_span_object;
                static long last_now;
                
-               public static DateTime Now 
-               {
-                       get     
-                       {
+               public static DateTime Now {
+                       get {
                                long now = GetNow ();
                                DateTime dt = new DateTime (now);
 
@@ -486,68 +475,49 @@ 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
+                               ret.encoded |= ((long)DateTimeKind.Local << KindShift);
                                return ret;
                        }
                }
 
-               public long Ticks
-               { 
-                       get     
-                       { 
-                               return ticks.Ticks;
+               public long Ticks { 
+                       get { 
+                               return encoded & TicksMask;
                        }
                }
        
-               public static DateTime Today 
-               {
+               public static DateTime Today {
                        get {
                                DateTime now = Now;
                                DateTime today = new DateTime (now.Year, now.Month, now.Day);
-#if NET_2_0
-                               today.kind = now.kind;
-#endif
+                               today.encoded |= ((long)DateTimeKind.Local << KindShift);
                                return today;
                        }
                }
 
-               public static DateTime UtcNow 
-               {
+               public static DateTime UtcNow {
                        get {
-#if NET_2_0
                                return new DateTime (GetNow (), DateTimeKind.Utc);
-#else
-                               return new DateTime (GetNow ());
-#endif
                        }
                }
 
-               public int Year 
-               {
-                       get 
-                       { 
-                               return FromTicks(Which.Year); 
+               public int Year {
+                       get { 
+                               return FromTicks (Which.Year); 
                        }
                }
 
-#if NET_2_0
                public DateTimeKind Kind {
                        get {
-                               return kind;
+                               return (DateTimeKind) ((ulong)encoded >> KindShift);
                        }
                }
-#endif
 
                /* methods */
 
                public DateTime Add (TimeSpan value)
                {
                        DateTime ret = AddTicks (value.Ticks);
-#if NET_2_0
-                       ret.kind = kind;
-#endif
                        return ret;
                }
 
@@ -558,13 +528,12 @@ namespace System
                
                public DateTime AddTicks (long value)
                {
-                       if ((value + ticks.Ticks) > MAX_VALUE_TICKS || (value + ticks.Ticks) < 0) {
+                       long res = value + (encoded & TicksMask);
+                       if (res < 0 || res > MAX_VALUE_TICKS)
                                throw new ArgumentOutOfRangeException();
-                       }
-                       DateTime ret = new DateTime (value + ticks.Ticks);
-#if NET_2_0
-                       ret.kind = kind;
-#endif
+
+                       DateTime ret = new DateTime (res);
+                       ret.encoded |= (encoded & KindMask);
                        return ret;
                }
 
@@ -576,10 +545,10 @@ namespace System
                public DateTime AddMilliseconds (double value)
                {
                        if ((value * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
-                                       (value * TimeSpan.TicksPerMillisecond) < long.MinValue) {
+                           (value * TimeSpan.TicksPerMillisecond) < long.MinValue) {
                                throw new ArgumentOutOfRangeException();
                        }
-                       long msticks = (long) (value * TimeSpan.TicksPerMillisecond);
+                       long msticks = (long) Math.Round (value * TimeSpan.TicksPerMillisecond);
 
                        return AddTicks (msticks);
                }
@@ -625,9 +594,7 @@ namespace System
                                day = maxday;
 
                        temp = new DateTime (year, month, day);
-#if NET_2_0
-                       temp.kind = kind;
-#endif
+                       temp.encoded |= encoded & KindMask;
                        return  temp.Add (this.TimeOfDay);
                }
 
@@ -643,9 +610,12 @@ namespace System
 
                public static int Compare (DateTime t1, DateTime t2)
                {
-                       if (t1.ticks < t2.ticks) 
+                       long t1t = t1.encoded & TicksMask;
+                       long t2t = t2.encoded & TicksMask;
+                       
+                       if (t1t < t2t) 
                                return -1;
-                       else if (t1.ticks > t2.ticks
+                       else if (t1t > t2t
                                return 1;
                        else
                                return 0;
@@ -663,10 +633,9 @@ namespace System
                        return Compare (this, (DateTime) value);
                }
 
-#if NET_2_0
                public bool IsDaylightSavingTime ()
                {
-                       if (kind == DateTimeKind.Utc)
+                       if ((int)((ulong)encoded >> KindShift) == (int) DateTimeKind.Utc)
                                return false;
                        return TimeZone.CurrentTimeZone.IsDaylightSavingTime (this);
                }
@@ -678,30 +647,26 @@ namespace System
 
                public bool Equals (DateTime value)
                {
-                       return value.ticks == ticks;
+                       return (value.encoded & TicksMask) == (encoded & TicksMask);
                }
 
                public long ToBinary ()
                {
-                       switch (kind) {
-                       case DateTimeKind.Utc:
-                               return Ticks | 0x4000000000000000;
-                       case DateTimeKind.Local:
+                       if ((encoded & ((long)DateTimeKind.Local << KindShift)) != 0)
                                return (long) ((ulong) ToUniversalTime ().Ticks | 0x8000000000000000);
-                       default:
-                               return Ticks;
-                       }
+                       
+                       return encoded;
                }
 
                public static DateTime FromBinary (long dateData)
                {
-                       switch ((ulong)dateData >> 62) {
-                       case 1:
-                               return new DateTime (dateData ^ 0x4000000000000000, DateTimeKind.Utc);
-                       case 0:
+                       switch ((ulong)dateData >> KindShift) {
+                       case 1: // Utc
+                               return new DateTime (dateData & TicksMask, DateTimeKind.Utc);
+                       case 0: // Unspecified
                                return new DateTime (dateData, DateTimeKind.Unspecified);
-                       default:
-                               return new DateTime (dateData & 0x3fffffffffffffff, DateTimeKind.Utc).ToLocalTime ();
+                       default: // Local
+                               return new DateTime (dateData & TicksMask, DateTimeKind.Utc).ToLocalTime ();
                        }
                }
 
@@ -710,19 +675,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 ;
@@ -742,12 +694,12 @@ namespace System
                        if (!(value is System.DateTime))
                                return false;
 
-                       return ((DateTime) value).ticks == ticks;
+                       return (((DateTime) value).encoded & TicksMask) == (encoded & TicksMask);
                }
 
                public static bool Equals (DateTime t1, DateTime t2 )
                {
-                       return (t1.ticks == t2.ticks );
+                       return (t1.encoded & TicksMask) == (t2.encoded & TicksMask);
                }
 
                public static DateTime FromFileTime (long fileTime) 
@@ -758,15 +710,13 @@ namespace System
                        return new DateTime (w32file_epoch + fileTime).ToLocalTime ();
                }
 
-#if NET_1_1
                public static DateTime FromFileTimeUtc (long fileTime) 
                {
                        if (fileTime < 0)
                                throw new ArgumentOutOfRangeException ("fileTime", "< 0");
 
-                       return new DateTime (w32file_epoch + fileTime);
+                       return new DateTime (w32file_epoch + fileTime, DateTimeKind.Utc);
                }
-#endif
 
                public static DateTime FromOADate (double d)
                {
@@ -811,10 +761,10 @@ namespace System
                {
                        DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
 //                     return GetDateTimeFormats (info.GetAllDateTimePatterns ());
-                       ArrayList al = new ArrayList ();
+                       var l = new List<string> ();
                        foreach (char c in "dDgGfFmMrRstTuUyY")
-                               al.AddRange (GetDateTimeFormats (c, info));
-                       return al.ToArray (typeof (string)) as string [];
+                               l.AddRange (GetDateTimeFormats (c, info));
+                       return l.ToArray ();
                }
 
                public string[] GetDateTimeFormats(char format,IFormatProvider provider )
@@ -849,16 +799,9 @@ 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 ()
                {
-                       return (int) ticks.Ticks;
+                       return (int) encoded;
                }
 
                public TypeCode GetTypeCode ()
@@ -889,8 +832,9 @@ namespace System
                                throw new ArgumentNullException ("s");
 
                        DateTime res;
+                       DateTimeOffset dto;
                        Exception exception = null;
-                       if (!CoreParse (s, provider, styles, out res, true, ref exception))
+                       if (!CoreParse (s, provider, styles, out res, out dto, true, ref exception))
                                throw exception;
                        
                        return res;
@@ -898,32 +842,40 @@ namespace System
 
                const string formatExceptionMessage = "String was not recognized as a valid DateTime.";
                
-               public static bool CoreParse (string s, IFormatProvider provider, DateTimeStyles styles,
-                                             out DateTime result, bool setExceptionOnError, ref Exception exception)
+               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);
+                       string[] allDateFormats = YearMonthDayFormats (dfi);
                        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))
+                               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))
+                                       if (_DoParse (s, firstPart, ParseTimeFormats [j], false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
                                                return true;
                                }
                        }
@@ -943,27 +895,27 @@ namespace System
                        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))
+                               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))
+                               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))
+                                       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))
+                                       if (_DoParse (s, firstPart, dateFormat, false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
                                                return true;
                                }
                        }
@@ -975,15 +927,8 @@ namespace System
                        if (!setExceptionOnError)
                                return false;
                        
-#if NET_2_0
                        // .NET 2.x does not throw an ArgumentOutOfRangeException, but .NET 1.1 does.
                        exception = new FormatException (formatExceptionMessage);
-#else
-                       if (longYear)
-                               exception = new ArgumentOutOfRangeException ("year", "Valid values are between 1 and 9999, inclusive.");
-                       else 
-                               exception = new FormatException (formatExceptionMessage);
-#endif
                        return false;
                }
 
@@ -992,16 +937,13 @@ namespace System
                        return ParseExact (s, format, provider, DateTimeStyles.None);
                }
 
-               private static string[] YearMonthDayFormats (DateTimeFormatInfo dfi, bool setExceptionOnError, ref Exception exc)
+               private static string[] YearMonthDayFormats (DateTimeFormatInfo dfi)
                {
                        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 (dayIndex == -1 || monthIndex == -1 || yearIndex == -1)
+                               return ParseGenericYearMonthDayFormats;
 
                        if (yearIndex < monthIndex)
                                if (monthIndex < dayIndex)
@@ -1010,9 +952,7 @@ namespace System
                                        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;
+                                       return ParseGenericYearMonthDayFormats;
                                }
                        else if (dayIndex < monthIndex)
                                return ParseDayMonthYearFormats;
@@ -1020,9 +960,7 @@ namespace System
                                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;
+                               return ParseGenericYearMonthDayFormats;
                        }
                }
 
@@ -1189,6 +1127,7 @@ namespace System
                                              string secondPart,
                                              bool exact,
                                              out DateTime result,
+                                             out DateTimeOffset dto,
                                              DateTimeFormatInfo dfi,
                                              DateTimeStyles style,
                                              bool firstPartIsDate,
@@ -1198,9 +1137,7 @@ namespace System
                        bool useutc = false;
                        bool use_invariant = false;
                        bool sloppy_parsing = false;
-#if !NET_2_0
-                       bool afterTimePart = firstPartIsDate && secondPart == "";
-#endif
+                       dto = new DateTimeOffset (0, TimeSpan.Zero);
                        bool flexibleTwoPartsParsing = !exact && secondPart != null;
                        incompleteFormat = false;
                        int valuePos = 0;
@@ -1214,6 +1151,9 @@ namespace System
                        if (format == null)
                                return false;
 
+                       if (s == null)
+                               return false;
+                               
                        if ((style & DateTimeStyles.AllowLeadingWhite) != 0) {
                                format = format.TrimStart (null);
 
@@ -1252,11 +1192,7 @@ namespace System
                                if (flexibleTwoPartsParsing && pos + num == 0)
                                {
                                        bool isLetter = IsLetter(s, valuePos);
-#if NET_2_0
                                        if (isLetter) {
-#else
-                                       if (afterTimePart && isLetter) {
-#endif
                                                if (s [valuePos] == 'Z')
                                                        num_parsed = 1;
                                                else
@@ -1310,10 +1246,6 @@ namespace System
                                                chars = format;
                                                len = chars.Length;
                                                isFirstPart = false;
-#if !NET_2_0
-                                               if (!firstPartIsDate || format == "")
-                                                       afterTimePart = true;
-#endif
                                                continue;
                                        }
                                        break;
@@ -1517,11 +1449,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;
@@ -1570,7 +1500,6 @@ namespace System
                                                        num_parsed = 0;
                                        }
                                        break;
-#if NET_2_0
                                case 'K':
                                        if (s [valuePos] == 'Z') {
                                                valuePos++;
@@ -1603,7 +1532,7 @@ namespace System
                                                        return false;
                                        }
                                        break;
-#endif
+
                                // LAMESPEC: This should be part of UTCpattern
                                // string and thus should not be considered here.
                                //
@@ -1663,9 +1592,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' &&
@@ -1681,7 +1608,6 @@ 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
@@ -1689,7 +1615,7 @@ namespace System
                        }
                        while (pos < len && chars [pos] == 'K') // 'K' can be mapped to nothing
                                pos++;
-#endif
+
                        if (pos < len)
                                return false;
 
@@ -1762,49 +1688,49 @@ namespace System
                        if (dayofweek != -1 && dayofweek != (int) result.DayOfWeek)
                                return false;
 
-                       TimeSpan utcoffset;
-
-                       bool adjustToUniversal = (style & DateTimeStyles.AdjustToUniversal) != 0;
-                       
-                       if (tzsign != -1) {
+                       if (tzsign == -1) {
+                               if (result != DateTime.MinValue) {
+                                       try {
+                                               dto = new DateTimeOffset (result);
+                                       } catch { } // We handle this error in DateTimeOffset.Parse
+                               }
+                       } else {
                                if (tzoffmin == -1)
                                        tzoffmin = 0;
                                if (tzoffset == -1)
                                        tzoffset = 0;
-                               if (tzsign == 1)
+                               if (tzsign == 1) {
                                        tzoffset = -tzoffset;
-
-                               utcoffset = new TimeSpan (tzoffset, tzoffmin, 0);
-                               long newticks = (result.ticks - utcoffset).Ticks;
+                                       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 - dto.Offset).Ticks;
                                if (newticks < 0)
                                        newticks += TimeSpan.TicksPerDay;
-                               result = new DateTime (false, new TimeSpan (newticks));
-#if NET_2_0
-                               result.kind = DateTimeKind.Utc;
+                               result = new DateTime (newticks, DateTimeKind.Utc);
                                if ((style & DateTimeStyles.RoundtripKind) != 0)
                                        result = result.ToLocalTime ();
-#endif
-                       }
-#if NET_2_0                                                    
-                       else if (useutc || ((style & DateTimeStyles.AssumeUniversal) != 0))
-                               result.kind = DateTimeKind.Utc;
+                       } else if (useutc || ((style & DateTimeStyles.AssumeUniversal) != 0))
+                               result.encoded |= ((long) DateTimeKind.Utc << KindShift);
                        else if ((style & DateTimeStyles.AssumeLocal) != 0)
-                               result.kind = DateTimeKind.Local;                                               
+                               result.encoded |= ((long) DateTimeKind.Local << KindShift);
 
                        bool adjustToLocal = !adjustToUniversal && (style & DateTimeStyles.RoundtripKind) == 0;
-                       if (result.kind != DateTimeKind.Unspecified)
-                       {                               
+                       if ((DateTimeKind)(((ulong) result.encoded >> KindShift)) != DateTimeKind.Unspecified) {
                                if (adjustToUniversal)
                                        result = result.ToUniversalTime ();
                                else if (adjustToLocal)
                                        result = result.ToLocalTime ();
                        }
-#else
-                       if (!adjustToUniversal && (useutc || tzsign != -1))
-                               result = result.ToLocalTime ();
-#endif
                        return true;
                }
+               
 
                public static DateTime ParseExact (string s, string format,
                                                   IFormatProvider provider, DateTimeStyles style)
@@ -1823,9 +1749,7 @@ namespace System
                                                   DateTimeStyles style)
                {
                        DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
-#if NET_2_0
                        CheckStyle (style);
-#endif
                        if (s == null)
                                throw new ArgumentNullException ("s");
                        if (formats == null)
@@ -1841,7 +1765,6 @@ namespace System
                        return result;
                }               
 
-#if NET_2_0
                private static void CheckStyle (DateTimeStyles style)
                {
                        if ( (style & DateTimeStyles.RoundtripKind) != 0)
@@ -1859,8 +1782,9 @@ namespace System
                        if (s != null){
                                try {
                                        Exception exception = null;
+                                       DateTimeOffset dto;
 
-                                       return CoreParse (s, null, DateTimeStyles.AllowWhiteSpaces, out result, false, ref exception);
+                                       return CoreParse (s, null, DateTimeStyles.AllowWhiteSpaces, out result, out dto, false, ref exception);
                                } catch { }
                        }
                        result = MinValue;
@@ -1872,8 +1796,9 @@ namespace System
                        if (s != null){
                                try {
                                        Exception exception = null;
+                                       DateTimeOffset dto;
                                        
-                                       return CoreParse (s, provider, styles, out result, false, ref exception);
+                                       return CoreParse (s, provider, styles, out result, out dto, false, ref exception);
                                } catch {}
                        } 
                        result = MinValue;
@@ -1897,13 +1822,17 @@ namespace System
                                                  DateTimeStyles style,
                                                  out DateTime result)
                {
-                       DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
+                       try {
+                               DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
 
-                       bool longYear = false;
-                       Exception e = null;
-                       return ParseExact (s, formats, dfi, style, out result, true, ref longYear, false, ref e);
+                               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,
@@ -1919,7 +1848,8 @@ namespace System
                                if (format == null || format == String.Empty)
                                        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;
                                }
@@ -1933,18 +1863,18 @@ namespace System
                
                public TimeSpan Subtract (DateTime value)
                {
-                       return new TimeSpan (ticks.Ticks) - value.ticks;
+                       return new TimeSpan (Ticks) - new TimeSpan (value.Ticks);
                }
 
                public DateTime Subtract(TimeSpan value)
                {
-                       TimeSpan newticks;
+                       long newticks;
 
-                       newticks = (new TimeSpan (ticks.Ticks)) - value;
-                       DateTime ret = new DateTime (true,newticks);
-#if NET_2_0
-                       ret.kind = kind;
-#endif
+                       newticks = Ticks - value.Ticks;
+                       if (newticks < 0 || newticks > MAX_VALUE_TICKS)
+                               throw new ArgumentOutOfRangeException ();
+                       DateTime ret = new DateTime (newticks);
+                       ret.encoded |= (encoded & KindMask);
                        return ret;
                }
 
@@ -1959,7 +1889,6 @@ namespace System
                        return(universalTime.Ticks - w32file_epoch);
                }
 
-#if NET_1_1
                public long ToFileTimeUtc()
                {
                        if (Ticks < w32file_epoch) {
@@ -1968,7 +1897,6 @@ namespace System
                        
                        return (Ticks - w32file_epoch);
                }
-#endif
 
                public string ToLongDateString()
                {
@@ -2070,169 +1998,167 @@ 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;
+                       try {
+                               long res = checked ((d.encoded & TicksMask) + t.Ticks);
+                               if (res < 0 || res > MAX_VALUE_TICKS){
+                                       throw new ArgumentOutOfRangeException ();
+                               }
+                               
+                               return new DateTime (res, d.Kind);
+                       } catch (OverflowException){
+                               throw new ArgumentOutOfRangeException ();
+                       }
                }
 
                public static bool operator ==(DateTime d1, DateTime d2)
                {
-                       return (d1.ticks == d2.ticks);
+                       return ((d1.encoded & TicksMask) == (d2.encoded & TicksMask));
                }
 
                public static bool operator >(DateTime t1,DateTime t2)
                {
-                       return (t1.ticks > t2.ticks);
+                       return ((t1.encoded & TicksMask) > (t2.encoded & TicksMask));
                }
 
                public static bool operator >=(DateTime t1,DateTime t2)
                {
-                       return (t1.ticks >= t2.ticks);
+                       return ((t1.encoded & TicksMask) >= (t2.encoded & TicksMask));
                }
 
                public static bool operator !=(DateTime d1, DateTime d2)
                {
-                       return (d1.ticks != d2.ticks);
+                       return ((d1.encoded & TicksMask) != (d2.encoded & TicksMask));
                }
 
-               public static bool operator <(DateTime t1,      DateTime t2)
+               public static bool operator <(DateTime t1, DateTime t2)
                {
-                       return (t1.ticks < t2.ticks );
+                       return ((t1.encoded & TicksMask) < (t2.encoded & TicksMask));
                }
 
-               public static bool operator <=(DateTime t1,DateTime t2)
+               public static bool operator <=(DateTime t1, DateTime t2)
                {
-                       return (t1.ticks <= t2.ticks);
+                       return ((t1.encoded & TicksMask) <= (t2.encoded & TicksMask));
                }
 
-               public static TimeSpan operator -(DateTime d1,DateTime d2)
+               public static TimeSpan operator -(DateTime d1, DateTime d2)
                {
-                       return new TimeSpan((d1.ticks - d2.ticks).Ticks);
+                       return new TimeSpan ((d1.encoded & TicksMask) - (d2.encoded & TicksMask));
                }
 
-               public static DateTime operator -(DateTime d,TimeSpan t)
+               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;
+                       try {
+                               long res = checked ((d.encoded & TicksMask) - t.Ticks);
+                               if (res < 0 || res > MAX_VALUE_TICKS)
+                                       throw new ArgumentOutOfRangeException ();
+                               return new DateTime (res, d.Kind);
+                       } catch (OverflowException){
+                               throw new ArgumentOutOfRangeException ();
+                       }
                }
 
-               bool IConvertible.ToBoolean(IFormatProvider provider)
+               bool IConvertible.ToBoolean (IFormatProvider provider)
                {
                        throw new InvalidCastException();
                }
                
-               byte IConvertible.ToByte(IFormatProvider provider)
+               byte IConvertible.ToByte (IFormatProvider provider)
                {
                        throw new InvalidCastException();
 
                }
 
-               char IConvertible.ToChar(IFormatProvider provider)
+               char IConvertible.ToChar (IFormatProvider provider)
                {
                        throw new InvalidCastException();
                }
 
-               System.DateTime IConvertible.ToDateTime(IFormatProvider provider)
+               System.DateTime IConvertible.ToDateTime (IFormatProvider provider)
                {
                        return this;
                } 
                
-               decimal IConvertible.ToDecimal(IFormatProvider provider)
+               decimal IConvertible.ToDecimal (IFormatProvider provider)
                {
                         throw new InvalidCastException();
                }
 
-               double IConvertible.ToDouble(IFormatProvider provider)
+               double IConvertible.ToDouble (IFormatProvider provider)
                {
                        throw new InvalidCastException();
                }
 
-               Int16 IConvertible.ToInt16(IFormatProvider provider)
+               Int16 IConvertible.ToInt16 (IFormatProvider provider)
                {
                        throw new InvalidCastException();
                }
 
-               Int32 IConvertible.ToInt32(IFormatProvider provider)
+               Int32 IConvertible.ToInt32 (IFormatProvider provider)
                {
                        throw new InvalidCastException();
                }
 
-               Int64 IConvertible.ToInt64(IFormatProvider provider)
+               Int64 IConvertible.ToInt64 (IFormatProvider provider)
                {
                        throw new InvalidCastException();
                }
 
-#if ONLY_1_1
-#pragma warning disable 3019
-               [CLSCompliant (false)]
-#endif
-               SByte IConvertible.ToSByte(IFormatProvider provider)
+               SByte IConvertible.ToSByte (IFormatProvider provider)
                {
                        throw new InvalidCastException();
                }
-#if ONLY_1_1
-#pragma warning restore 3019
-#endif
 
-               Single IConvertible.ToSingle(IFormatProvider provider)
+               Single IConvertible.ToSingle (IFormatProvider provider)
                {
                        throw new InvalidCastException();
                }
 
-               object IConvertible.ToType (Type type, IFormatProvider provider)
+               object IConvertible.ToType (Type targetType, IFormatProvider provider)
                {
-                       if (type == null)
-                               throw new ArgumentNullException ("type");
+                       if (targetType == null)
+                               throw new ArgumentNullException ("targetType");
 
-                       if (type == typeof (DateTime))
+                       if (targetType == typeof (DateTime))
                                return this;
-                       else if (type == typeof (String))
+                       else if (targetType == typeof (String))
                                return this.ToString (provider);
-                       else if (type == typeof (Object))
+                       else if (targetType == typeof (Object))
                                return this;
                        else
                                throw new InvalidCastException();
                }
 
-#if ONLY_1_1
-#pragma warning disable 3019
-               [CLSCompliant (false)]
-#endif
-               UInt16 IConvertible.ToUInt16(IFormatProvider provider)
+               UInt16 IConvertible.ToUInt16 (IFormatProvider provider)
                {
                        throw new InvalidCastException();
                }
-#if ONLY_1_1
-#pragma warning restore 3019
-#endif
 
-#if ONLY_1_1
-#pragma warning disable 3019
-               [CLSCompliant (false)]
-#endif
-               UInt32 IConvertible.ToUInt32(IFormatProvider provider)
+               UInt32 IConvertible.ToUInt32 (IFormatProvider provider)
                {
                        throw new InvalidCastException();
                }
-#if ONLY_1_1
-#pragma warning restore 3019
-#endif
 
-#if ONLY_1_1
-#pragma warning disable 3019
-               [CLSCompliant (false)]
-#endif
-               UInt64 IConvertible.ToUInt64(IFormatProvider provider)
+               UInt64 IConvertible.ToUInt64 (IFormatProvider provider)
                {
                        throw new InvalidCastException();
                }
-#if ONLY_1_1
-#pragma warning restore 3019
+
+               void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
+               {
+                       long t = Ticks;
+                       info.AddValue ("ticks", t);
+
+                       // This is the new .NET format, encodes the kind on the top bits
+                       info.AddValue ("dateData", encoded);
+               }
+               
+#if MONOTOUCH
+               static DateTime () {
+                       if (MonoTouchAOTHelper.FalseFlag) {
+                               var comparer = new System.Collections.Generic.GenericComparer <DateTime> ();
+                               var eqcomparer = new System.Collections.Generic.GenericEqualityComparer <DateTime> ();
+                       }
+               }
 #endif
        }
 }