Merge pull request #1304 from slluis/mac-proxy-autoconfig
[mono.git] / mcs / class / corlib / System / DateTimeOffset.cs
index 8add5b6d2086f41584d3afc67d063ff29c65daae..1267f9270decadd2c3d02078de4a3f94cf9feb87 100644 (file)
@@ -1,11 +1,12 @@
 /*
- * System.DateTimeOffset
+ * System.DateTimeOffset.cs
  *
  * Author(s)
  *     Stephane Delcroix <stephane@delcroix.org>
  *     Marek Safar (marek.safar@gmail.com)
  *
  *  Copyright (C) 2007 Novell, Inc (http://www.novell.com) 
+ *  Copyright 2012 Xamarin, Inc (http://www.xamarin.com) 
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -28,8 +29,6 @@
  */
 
 
-#if NET_2_0 // Introduced by .NET 3.5 for 2.0 mscorlib
-
 using System.Globalization;
 using System.Runtime.InteropServices;
 using System.Runtime.Serialization;
@@ -41,6 +40,14 @@ namespace System
        [StructLayout (LayoutKind.Auto)]
        public struct DateTimeOffset : IComparable, IFormattable, ISerializable, IDeserializationCallback, IComparable<DateTimeOffset>, IEquatable<DateTimeOffset>
        {
+#if MONOTOUCH
+               static DateTimeOffset () {
+                       if (MonoTouchAOTHelper.FalseFlag) {
+                               var comparer = new System.Collections.Generic.GenericComparer <DateTimeOffset> ();
+                               var eqcomparer = new System.Collections.Generic.GenericEqualityComparer <DateTimeOffset> ();
+                       }
+               }
+#endif
                public static readonly DateTimeOffset MaxValue = new DateTimeOffset (DateTime.MaxValue, TimeSpan.Zero);
                public static readonly DateTimeOffset MinValue = new DateTimeOffset (DateTime.MinValue, TimeSpan.Zero);
                
@@ -103,52 +110,52 @@ namespace System
 
                public DateTimeOffset Add (TimeSpan timeSpan)
                {
-                       return new DateTimeOffset (dt.Add (timeSpan), utc_offset);
+                       return new DateTimeOffset (dt.Add (timeSpan).Ticks, utc_offset);
                }
        
                public DateTimeOffset AddDays (double days)
                {
-                       return new DateTimeOffset (dt.AddDays (days), utc_offset);      
+                       return new DateTimeOffset (dt.AddDays (days).Ticks, utc_offset);        
                }
                
                public DateTimeOffset AddHours (double hours)
                {
-                       return new DateTimeOffset (dt.AddHours (hours), utc_offset);
+                       return new DateTimeOffset (dt.AddHours (hours).Ticks, utc_offset);
                }
 
-               public static DateTimeOffset operator + (DateTimeOffset dateTimeTz, TimeSpan timeSpan)
+               public static DateTimeOffset operator + (DateTimeOffset dateTimeOffset, TimeSpan timeSpan)
                {
-                       return dateTimeTz.Add (timeSpan);
+                       return dateTimeOffset.Add (timeSpan);
                }
 
                public DateTimeOffset AddMilliseconds (double milliseconds)
                {
-                       return new DateTimeOffset (dt.AddMilliseconds (milliseconds), utc_offset);
+                       return new DateTimeOffset (dt.AddMilliseconds (milliseconds).Ticks, utc_offset);
                }
 
                public DateTimeOffset AddMinutes (double minutes)
                {
-                       return new DateTimeOffset (dt.AddMinutes (minutes), utc_offset);        
+                       return new DateTimeOffset (dt.AddMinutes (minutes).Ticks, utc_offset);  
                }
 
                public DateTimeOffset AddMonths (int months)
                {
-                       return new DateTimeOffset (dt.AddMonths (months), utc_offset);
+                       return new DateTimeOffset (dt.AddMonths (months).Ticks, utc_offset);
                }
 
                public DateTimeOffset AddSeconds (double seconds)
                {
-                       return new DateTimeOffset (dt.AddSeconds (seconds), utc_offset);
+                       return new DateTimeOffset (dt.AddSeconds (seconds).Ticks, utc_offset);
                }
 
                public DateTimeOffset AddTicks (long ticks)
                {
-                       return new DateTimeOffset (dt.AddTicks (ticks), utc_offset);    
+                       return new DateTimeOffset (dt.AddTicks (ticks).Ticks, utc_offset);      
                }
 
                public DateTimeOffset AddYears (int years)
                {
-                       return new DateTimeOffset (dt.AddYears (years), utc_offset);
+                       return new DateTimeOffset (dt.AddYears (years).Ticks, utc_offset);
                }
 
                public static int Compare (DateTimeOffset first, DateTimeOffset second)
@@ -161,9 +168,9 @@ namespace System
                        return UtcDateTime.CompareTo (other.UtcDateTime);
                }
 
-               public int CompareTo (object other)
+               int IComparable.CompareTo (object obj)
                {
-                       return CompareTo ((DateTimeOffset) other);
+                       return CompareTo ((DateTimeOffset) obj);
                }
 
                public static bool operator == (DateTimeOffset left, DateTimeOffset right)
@@ -176,9 +183,11 @@ namespace System
                        return UtcDateTime == other.UtcDateTime;
                }
 
-               public override bool Equals (object other)
+               public override bool Equals (object obj)
                {
-                       return UtcDateTime == ((DateTimeOffset) other).UtcDateTime;
+                       if (obj is DateTimeOffset)
+                               return UtcDateTime == ((DateTimeOffset) obj).UtcDateTime;
+                       return false;
                }
 
                public static bool Equals (DateTimeOffset first, DateTimeOffset second)
@@ -205,13 +214,34 @@ namespace System
                        return dt.GetHashCode () ^ utc_offset.GetHashCode ();
                }
 
+               [System.Security.Permissions.SecurityPermission (System.Security.Permissions.SecurityAction.LinkDemand, SerializationFormatter = true)]
                void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
                {
                        if (info == null)
                                throw new ArgumentNullException ("info");
-
-                       info.AddValue ("datetime", dt);
-                       info.AddValue ("offset", utc_offset);
+                       // An example SOAP serialization on MSFT is the following, so field 
+                       // names "DateTime" and "OffsetMinutes":
+                       //    <SOAP-ENV:Envelope ...>
+                       //    <SOAP-ENV:Body>
+                       //    <a1:DateTimeOffset id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/ns/System">
+                       //    <DateTime xsi:type="xsd:dateTime">2007-01-02T12:30:50.0000000+00:00</DateTime>
+                       //    <OffsetMinutes>0</OffsetMinutes>
+                       //    </a1:DateTimeOffset>
+                       //    </SOAP-ENV:Body>
+                       //    </SOAP-ENV:Envelope>
+                       DateTime dt0 = new DateTime (dt.Ticks).Subtract (utc_offset);
+                       info.AddValue ("DateTime", dt0);
+                       // MSFT BinaryFormatter output contains primitive code 6, i.e. Int16.
+                       info.AddValue ("OffsetMinutes", (Int16)utc_offset.TotalMinutes);
+               }
+
+               [System.Security.Permissions.SecurityPermission (System.Security.Permissions.SecurityAction.LinkDemand, SerializationFormatter = true)]
+               private DateTimeOffset(SerializationInfo info, StreamingContext context)
+               {
+                       DateTime dt0 = (DateTime)info.GetValue ("DateTime", typeof(DateTime));
+                       Int16 totalMinutes = info.GetInt16 ("OffsetMinutes");
+                       utc_offset = TimeSpan.FromMinutes(totalMinutes);
+                       dt = dt0.Add(utc_offset);
                }
 
                public static bool operator > (DateTimeOffset left, DateTimeOffset right)
@@ -259,13 +289,25 @@ namespace System
                        return Parse (input, formatProvider, DateTimeStyles.AllowWhiteSpaces);
                }
 
-               [MonoTODO]
                public static DateTimeOffset Parse (string input, IFormatProvider formatProvider, DateTimeStyles styles)
                {
                        if (input == null)
                                throw new ArgumentNullException ("input");
 
-                       throw new NotImplementedException ();
+                       DateTime d;
+                       DateTimeOffset dto;
+                       Exception exception = null;
+                       try {
+                               if (!DateTime.CoreParse (input, formatProvider, styles, out d, out dto, true, ref exception))
+                                       throw exception;
+                       } catch (ArgumentOutOfRangeException ex) {
+                               throw new FormatException ("The UTC representation falls outside the 1-9999 year range", ex);
+                       }
+
+                       if (d.Ticks != 0 && dto.Ticks == 0)
+                               throw new FormatException ("The UTC representation falls outside the 1-9999 year range");
+
+                       return dto;
                }
 
                public static DateTimeOffset ParseExact (string input, string format, IFormatProvider formatProvider)
@@ -301,311 +343,29 @@ namespace System
                        if ((styles & DateTimeStyles.AssumeLocal) != 0 && (styles & DateTimeStyles.AssumeUniversal) != 0)
                                throw new ArgumentException ("styles parameter contains incompatible flags");
 
-                       if ((styles & DateTimeStyles.None) != 0 && (styles & DateTimeStyles.AllowWhiteSpaces) != 0)
-                               throw new ArgumentException ("styles parameter contains incompatible flags");
-
+                       DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (formatProvider);
+                       DateTime d;
                        DateTimeOffset result;
-                       if (!ParseExact (input, formats, DateTimeFormatInfo.GetInstance (formatProvider), styles, out result))
-                               throw new FormatException ();
-
-                       return result;
-               }
-
-               private static bool ParseExact (string input, string [] formats,
-                               DateTimeFormatInfo dfi, DateTimeStyles styles, out DateTimeOffset ret)
-               {
-                       foreach (string format in formats)
-                       {
-                               if (format == null || format == String.Empty)
-                                       throw new FormatException ("Invlid Format Sting");
-
-                               DateTimeOffset result;
-                               if (DoParse (input, format, false, out result, dfi, styles)) {
-                                       ret = result;
-                                       return true;
-                               }
-                       }
-                       ret = DateTimeOffset.MinValue;
-                       return false;
-               }
-
-               private static bool DoParse (string input, 
-                               string format,
-                               bool exact,
-                               out DateTimeOffset result,
-                               DateTimeFormatInfo dfi,
-                               DateTimeStyles styles)
-               {
-                       if ((styles & DateTimeStyles.AllowLeadingWhite) != 0) {
-                               format = format.TrimStart (null);
-                               input = input.TrimStart (null);
-                       }
-
-                       if ((styles & DateTimeStyles.AllowTrailingWhite) != 0) {
-                               format = format.TrimEnd (null);
-                               input = input.TrimEnd (null);
-                       }
-
-                       bool allow_white_spaces = false;
-                       if ((styles & DateTimeStyles.AllowInnerWhite) != 0)
-                               allow_white_spaces = true;
-
-                       bool useutc = false, use_invariants = false;
-                       if (format.Length == 1)
-                               format = DateTimeUtils.GetStandardPattern (format[0], dfi, out useutc, out use_invariants, true);
-               
-                       int year = -1;
-                       int month = -1;
-                       int day = -1;
-                       int hour = -1;
-                       int minute = -1;
-                       TimeSpan offset = TimeSpan.Zero;
-
-                       int fi = 0; //format iterator
-                       int ii = 0; //input iterator
-                       while (fi < format.Length) {
-                               int tokLen;
-                               char ch = format [fi];
-
-                               switch (ch) {
-                               case 'd':
-                                       tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
-                                       if (day != -1 || tokLen > 4) {
-                                               result = MinValue;
-                                               return false;
-                                       }
-                                       if (tokLen <= 2)
-                                               ii += ParseNumber (input, ii, 2, tokLen == 2, allow_white_spaces, out day);
-                                       else {
-                                               int day_of_week;
-                                               ii += ParseEnum (input, ii, tokLen == 3 ? dfi.AbbreviatedDayNames : dfi.DayNames, allow_white_spaces, out day_of_week); 
-                                       } 
-                                       break;
-                               case 'h':
-                                       tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
-                                       if (hour != -1 || tokLen > 2) {
-                                               result = MinValue;
-                                               return false;
-                                       }
-                                       ii += ParseNumber (input, ii, 2, tokLen == 2, allow_white_spaces, out hour);
-                                       break;
-                               case 'H':
-                                       tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
-                                       if (hour != -1 || tokLen > 2) {
-                                               result = MinValue;
-                                               return false;
-                                       }
-                                       ii += ParseNumber (input, ii, 2, tokLen == 2, allow_white_spaces, out hour);
-                                       break;
-                               case 'm':
-                                       tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
-                                       if (minute != -1 || tokLen > 2) {
-                                               result = MinValue;
-                                               return false;
-                                       }
-                                       ii += ParseNumber (input, ii, 2, tokLen == 2, allow_white_spaces, out minute);
-                                       break;
-                               case 'M':
-                                       tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
-                                       if (month != -1 || tokLen > 4) {
-                                               result = MinValue;
-                                               return false;
-                                       }
-                                       if (tokLen <= 2)
-                                               ii += ParseNumber (input, ii, 2, tokLen == 2, allow_white_spaces, out month);
-                                       else {
-                                               ii += ParseEnum (input, ii, tokLen == 3 ? dfi.AbbreviatedMonthNames : dfi.MonthNames, allow_white_spaces, out month);
-                                               month += 1;
-                                       }
-
-                                       break;
-                               case 't':
-                                       tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
-                                       switch (tokLen) {
-                                               case 1:
-                                                       if (input [ii] == dfi.PMDesignator [0]) {
-                                                               if (hour == -1)
-                                                                       hour = 0;
-                                                               hour += 12;
-                                                       } else if (input [ii] != dfi.AMDesignator [0])
-                                                               throw new FormatException ();
-                                                       ii ++;
-                                                       break;
-                                               case 2:
-                                                       if (input.Substring (ii).StartsWith (dfi.PMDesignator)) {
-                                                               if (hour == -1)
-                                                                       hour = 0;
-                                                               hour += 12;
-                                                               ii += dfi.PMDesignator.Length;
-                                                       } else if (input.Substring (ii).StartsWith (dfi.AMDesignator))
-                                                               ii += dfi.AMDesignator.Length;
-                                                       else
-                                                               throw new FormatException ();
-                                                       break;
-
-                                               default:
-                                                       throw new FormatException ();
-                                                       break;
-                                       }
-                                       break;
-                               case 'y':
-                                       tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
-                                       switch (tokLen) {
-                                               case 1:
-                                                       int l = 1;
-                                                       if (input.Length != ii + 1 && System.Char.IsDigit (input[ii + 1]))
-                                                               l = 2;
-                                                       year = Int32.Parse (input.Substring (ii, l));
-                                                       year += DateTime.Now.Year - DateTime.Now.Year % 100;
-                                                       ii += l;
-                                                       break;
-                                               case 2:
-                                                       year = Int32.Parse (input.Substring (ii, 2));
-                                                       year += DateTime.Now.Year - DateTime.Now.Year % 100;
-                                                       ii += 2;
-                                                       break;
-                                               case 3:
-                                                       throw new NotImplementedException ();
-                                                       //ToString ("yyy") seems to print 4-digits year...
-                                                       year = Int32.Parse (input.Substring (ii, 3));
-                                                       year += DateTime.Now.Year - DateTime.Now.Year % 1000;
-                                                       ii += 3;
-                                                       break;
-                                               default:
-                                                       year = Int32.Parse (input.Substring (ii, tokLen));
-                                                       ii += tokLen;
-                                                       break;
-                                       }
-                                       break;
-                               case 'z':
-                                       tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
-                                       int off_h, off_m = 0, sign;
-                                       switch (input[ii]) {
-                                               case '+': sign = 1; break;
-                                               case '-': sign = -1; break;
-                                               default:
-                                                       throw new FormatException ();
-                                                       break;
-                                       }
-                                       ii ++;
-                                       switch (tokLen) {
-                                               case 1:
-                                                       int l = 1;
-                                                       if (input.Length != ii + 1 && System.Char.IsDigit (input[ii + 1]))
-                                                               l = 2;
-                                                       off_h = Int32.Parse (input.Substring (ii, l));
-                                                       break;
-                                               case 2:
-                                                       off_h = Int32.Parse (input.Substring (ii, 2));
-                                                       ii += 2;
-                                                       break;
-                                               case 3:
-                                                       off_h = Int32.Parse (input.Substring (ii, 2));
-                                                       ii += 2;
-                                                       if (input [ii++] != ':')
-                                                               throw new FormatException ();
-                                                       off_m = Int32.Parse (input.Substring (ii, 2));
-                                                       ii += 2;
-                                                       break;
-                                               default:
-                                                       throw new FormatException ();
-                                                       break;
-                                       }
-                                       offset = new TimeSpan (sign * off_h, sign * off_m, 0);
-                                       break;
-                               case ':':
-                                       tokLen = 1;
-                                       if (!input.Substring (ii).StartsWith (dfi.TimeSeparator))
-                                               throw new FormatException ();
-                                       ii += dfi.TimeSeparator.Length;
-                                       break;
-                               case '/':
-                                       tokLen = 1;
-                                       if (!input.Substring (ii).StartsWith (dfi.DateSeparator))
-                                               throw new FormatException ();
-                                       ii += dfi.DateSeparator.Length;
-                                       break;
-                               case '%':
-                                       if (fi != 0)
-                                               throw new FormatException ();
-                                       tokLen = 1;
-                                       break;
-                               case ' ':
-                                       if (input[ii] != ' ')
-                                               throw new FormatException ();
-                                       tokLen = 1;
-                                       ii++;
-                                       break;
-                               default:
-                                       tokLen = 1;
-                                       ii++;
-                                       Console.WriteLine ("un-parsed character: {0}", ch);
-                                       break;
-                               }
-                               fi += tokLen;
-                       }
-
-                       //Console.WriteLine ("{0}-{1}-{2} {3}:{4} {5}", year, month, day, hour, minute, offset);
-
-                       if (day > 0 && month > 0 && year > 0 && hour > 0 && minute > 0) {
-                               result = new DateTimeOffset (year, month, day, hour, minute, 0, offset);
-                               return true;
-                       }
-                       if (day > 0 && month > 0 && year > 0) {
-                               result = new DateTimeOffset (year, month, day, 0, 0, 0, offset);
-                               return true;
+                       Exception exception = null;
+                       bool longYear = false;
+                       try {
+                               if (!DateTime.CoreParseExact (input, formats, dfi, styles, out d, out result, true, ref longYear, true, ref exception, true))
+                                       throw exception;
+                       } catch (ArgumentOutOfRangeException ex) {
+                               throw new FormatException ("The UTC representation falls outside the 1-9999 year range", ex);
                        }
 
-                       result = DateTimeOffset.MinValue;
-                       return false;
-               }
-
-               private static int ParseNumber (string input, int pos, int digits, bool leading_zero, bool allow_leading_white, out int result)
-               {
-                       int char_parsed = 0;
-                       int digit_parsed = 0;
-                       result = 0;
-                       for (; allow_leading_white && pos < input.Length && input[pos] == ' '; pos++, char_parsed++)
-                               ;
-
-                       for (; pos < input.Length && Char.IsDigit (input[pos]) && digits > 0; pos ++, char_parsed++, digit_parsed++, digits --)
-                               result = 10 * result + (byte) (input[pos] - '0');
-
-                       if (leading_zero && digits > 0)
-                               throw new FormatException ();
-
-                       return char_parsed;
-               }
-
-               private static int ParseEnum (string input, int pos, string [] enums, bool allow_leading_white, out int result)
-               {
-                       int char_parsed = 0;
-                       result = -1;
-                       for (; allow_leading_white && pos < input.Length && input[pos] == ' '; pos++, char_parsed++)
-                               ;
-                       
-                       for (int i = 0; i < enums.Length; i++)
-                               if (input.Substring(pos).StartsWith (enums [i])) {
-                                       result = i;
-                                       break;
-                               }
-
-                       if (result >= 0)
-                               char_parsed += enums[result].Length;
-
-                       return char_parsed;
-                               
-                       
+                       return result;
                }
 
-               public TimeSpan Subtract (DateTimeOffset other)
+               public TimeSpan Subtract (DateTimeOffset value)
                {
-                       return UtcDateTime - other.UtcDateTime;
+                       return UtcDateTime - value.UtcDateTime;
                }
 
-               public DateTimeOffset Subtract (TimeSpan timeSpan)
+               public DateTimeOffset Subtract (TimeSpan value)
                {
-                       return Add (-timeSpan);
+                       return Add (-value);
                }
 
                public static TimeSpan operator - (DateTimeOffset left, DateTimeOffset right)
@@ -613,9 +373,9 @@ namespace System
                        return left.Subtract (right);
                }
 
-               public static DateTimeOffset operator - (DateTimeOffset dateTimeTz, TimeSpan timeSpan)
+               public static DateTimeOffset operator - (DateTimeOffset dateTimeOffset, TimeSpan timeSpan)
                {
-                       return dateTimeTz.Subtract (timeSpan);  
+                       return dateTimeOffset.Subtract (timeSpan);      
                }
 
                public long ToFileTime ()
@@ -796,4 +556,3 @@ namespace System
                }
        }
 }
-#endif