/*
- * 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
*/
-#if NET_2_0 // Introduced by .NET 3.5 for 2.0 mscorlib
-
using System.Globalization;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
[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);
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)
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)
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)
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)
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)
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)
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 ()
}
}
}
-#endif