Jo Shields 8b9b85e7f5 Imported Upstream version 3.10.0
Former-commit-id: 172c8e3c300b39d5785c7a3e8dfb08ebdbc1a99b
2014-10-04 11:27:48 +01:00

559 lines
16 KiB
C#

/*
* 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
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System.Globalization;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Text;
namespace System
{
[Serializable]
[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);
DateTime dt;
TimeSpan utc_offset;
public DateTimeOffset (DateTime dateTime)
{
dt = dateTime;
if (dateTime.Kind == DateTimeKind.Utc)
utc_offset = TimeSpan.Zero;
else
utc_offset = TimeZone.CurrentTimeZone.GetUtcOffset (dateTime);
if (UtcDateTime < DateTime.MinValue || UtcDateTime > DateTime.MaxValue)
throw new ArgumentOutOfRangeException ("The UTC date and time that results from applying the offset is earlier than MinValue or later than MaxValue.");
}
public DateTimeOffset (DateTime dateTime, TimeSpan offset)
{
if (dateTime.Kind == DateTimeKind.Utc && offset != TimeSpan.Zero)
throw new ArgumentException ("dateTime.Kind equals Utc and offset does not equal zero.");
if (dateTime.Kind == DateTimeKind.Local && offset != TimeZone.CurrentTimeZone.GetUtcOffset (dateTime))
throw new ArgumentException ("dateTime.Kind equals Local and offset does not equal the offset of the system's local time zone.");
if (offset.Ticks % TimeSpan.TicksPerMinute != 0)
throw new ArgumentException ("offset is not specified in whole minutes.");
if (offset < new TimeSpan (-14, 0 ,0) || offset > new TimeSpan (14, 0, 0))
throw new ArgumentOutOfRangeException ("offset is less than -14 hours or greater than 14 hours.");
dt = dateTime;
utc_offset = offset;
if (UtcDateTime < DateTime.MinValue || UtcDateTime > DateTime.MaxValue)
throw new ArgumentOutOfRangeException ("The UtcDateTime property is earlier than MinValue or later than MaxValue.");
}
public DateTimeOffset (long ticks, TimeSpan offset) : this (new DateTime (ticks), offset)
{
}
public DateTimeOffset (int year, int month, int day, int hour, int minute, int second, TimeSpan offset) :
this (new DateTime (year, month, day, hour, minute, second), offset)
{
}
public DateTimeOffset (int year, int month, int day, int hour, int minute, int second, int millisecond, TimeSpan offset) :
this (new DateTime (year, month, day, hour, minute, second, millisecond), offset)
{
}
public DateTimeOffset (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, TimeSpan offset) :
this (new DateTime (year, month, day, hour, minute, second, millisecond, calendar), offset)
{
}
public DateTimeOffset Add (TimeSpan timeSpan)
{
return new DateTimeOffset (dt.Add (timeSpan).Ticks, utc_offset);
}
public DateTimeOffset AddDays (double days)
{
return new DateTimeOffset (dt.AddDays (days).Ticks, utc_offset);
}
public DateTimeOffset AddHours (double hours)
{
return new DateTimeOffset (dt.AddHours (hours).Ticks, utc_offset);
}
public static DateTimeOffset operator + (DateTimeOffset dateTimeOffset, TimeSpan timeSpan)
{
return dateTimeOffset.Add (timeSpan);
}
public DateTimeOffset AddMilliseconds (double milliseconds)
{
return new DateTimeOffset (dt.AddMilliseconds (milliseconds).Ticks, utc_offset);
}
public DateTimeOffset AddMinutes (double minutes)
{
return new DateTimeOffset (dt.AddMinutes (minutes).Ticks, utc_offset);
}
public DateTimeOffset AddMonths (int months)
{
return new DateTimeOffset (dt.AddMonths (months).Ticks, utc_offset);
}
public DateTimeOffset AddSeconds (double seconds)
{
return new DateTimeOffset (dt.AddSeconds (seconds).Ticks, utc_offset);
}
public DateTimeOffset AddTicks (long ticks)
{
return new DateTimeOffset (dt.AddTicks (ticks).Ticks, utc_offset);
}
public DateTimeOffset AddYears (int years)
{
return new DateTimeOffset (dt.AddYears (years).Ticks, utc_offset);
}
public static int Compare (DateTimeOffset first, DateTimeOffset second)
{
return first.CompareTo (second);
}
public int CompareTo (DateTimeOffset other)
{
return UtcDateTime.CompareTo (other.UtcDateTime);
}
int IComparable.CompareTo (object obj)
{
return CompareTo ((DateTimeOffset) obj);
}
public static bool operator == (DateTimeOffset left, DateTimeOffset right)
{
return left.Equals (right);
}
public bool Equals (DateTimeOffset other)
{
return UtcDateTime == other.UtcDateTime;
}
public override bool Equals (object obj)
{
if (obj is DateTimeOffset)
return UtcDateTime == ((DateTimeOffset) obj).UtcDateTime;
return false;
}
public static bool Equals (DateTimeOffset first, DateTimeOffset second)
{
return first.Equals (second);
}
public bool EqualsExact (DateTimeOffset other)
{
return dt == other.dt && utc_offset == other.utc_offset;
}
public static DateTimeOffset FromFileTime (long fileTime)
{
if (fileTime < 0 || fileTime > MaxValue.Ticks)
throw new ArgumentOutOfRangeException ("fileTime is less than zero or greater than DateTimeOffset.MaxValue.Ticks.");
return new DateTimeOffset (DateTime.FromFileTime (fileTime), TimeZone.CurrentTimeZone.GetUtcOffset (DateTime.FromFileTime (fileTime)));
}
public override int GetHashCode ()
{
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");
// 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 left.UtcDateTime > right.UtcDateTime;
}
public static bool operator >= (DateTimeOffset left, DateTimeOffset right)
{
return left.UtcDateTime >= right.UtcDateTime;
}
public static implicit operator DateTimeOffset (DateTime dateTime)
{
return new DateTimeOffset (dateTime);
}
public static bool operator != (DateTimeOffset left, DateTimeOffset right)
{
return left.UtcDateTime != right.UtcDateTime;
}
public static bool operator < (DateTimeOffset left, DateTimeOffset right)
{
return left.UtcDateTime < right.UtcDateTime;
}
public static bool operator <= (DateTimeOffset left, DateTimeOffset right)
{
return left.UtcDateTime <= right.UtcDateTime;
}
[MonoTODO]
void IDeserializationCallback.OnDeserialization (object sender)
{
}
public static DateTimeOffset Parse (string input)
{
return Parse (input, null);
}
public static DateTimeOffset Parse (string input, IFormatProvider formatProvider)
{
return Parse (input, formatProvider, DateTimeStyles.AllowWhiteSpaces);
}
public static DateTimeOffset Parse (string input, IFormatProvider formatProvider, DateTimeStyles styles)
{
if (input == null)
throw new ArgumentNullException ("input");
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)
{
return ParseExact (input, format, formatProvider, DateTimeStyles.AssumeLocal);
}
public static DateTimeOffset ParseExact (string input, string format, IFormatProvider formatProvider, DateTimeStyles styles)
{
if (format == null)
throw new ArgumentNullException ("format");
if (format == String.Empty)
throw new FormatException ("format is an empty string");
return ParseExact (input, new string [] {format}, formatProvider, styles);
}
public static DateTimeOffset ParseExact (string input, string[] formats, IFormatProvider formatProvider, DateTimeStyles styles)
{
if (input == null)
throw new ArgumentNullException ("input");
if (input == String.Empty)
throw new FormatException ("input is an empty string");
if (formats == null)
throw new ArgumentNullException ("formats");
if (formats.Length == 0)
throw new FormatException ("Invalid format specifier");
if ((styles & DateTimeStyles.AssumeLocal) != 0 && (styles & DateTimeStyles.AssumeUniversal) != 0)
throw new ArgumentException ("styles parameter contains incompatible flags");
DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (formatProvider);
DateTime d;
DateTimeOffset result;
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);
}
return result;
}
public TimeSpan Subtract (DateTimeOffset value)
{
return UtcDateTime - value.UtcDateTime;
}
public DateTimeOffset Subtract (TimeSpan value)
{
return Add (-value);
}
public static TimeSpan operator - (DateTimeOffset left, DateTimeOffset right)
{
return left.Subtract (right);
}
public static DateTimeOffset operator - (DateTimeOffset dateTimeOffset, TimeSpan timeSpan)
{
return dateTimeOffset.Subtract (timeSpan);
}
public long ToFileTime ()
{
return UtcDateTime.ToFileTime ();
}
public DateTimeOffset ToLocalTime ()
{
return new DateTimeOffset (UtcDateTime.ToLocalTime (), TimeZone.CurrentTimeZone.GetUtcOffset (UtcDateTime.ToLocalTime ()));
}
public DateTimeOffset ToOffset (TimeSpan offset)
{
return new DateTimeOffset (dt - utc_offset + offset, offset);
}
public override string ToString ()
{
return ToString (null, null);
}
public string ToString (IFormatProvider formatProvider)
{
return ToString (null, formatProvider);
}
public string ToString (string format)
{
return ToString (format, null);
}
public string ToString (string format, IFormatProvider formatProvider)
{
DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance(formatProvider);
if (format == null || format == String.Empty)
format = dfi.ShortDatePattern + " " + dfi.LongTimePattern + " zzz";
bool to_utc = false, use_invariant = false;
if (format.Length == 1) {
char fchar = format [0];
try {
format = DateTimeUtils.GetStandardPattern (fchar, dfi, out to_utc, out use_invariant, true);
} catch {
format = null;
}
if (format == null)
throw new FormatException ("format is not one of the format specifier characters defined for DateTimeFormatInfo");
}
return to_utc ? DateTimeUtils.ToString (UtcDateTime, TimeSpan.Zero, format, dfi) : DateTimeUtils.ToString (DateTime, Offset, format, dfi);
}
public DateTimeOffset ToUniversalTime ()
{
return new DateTimeOffset (UtcDateTime, TimeSpan.Zero);
}
public static bool TryParse (string input, out DateTimeOffset result)
{
try {
result = Parse (input);
return true;
} catch {
result = MinValue;
return false;
}
}
public static bool TryParse (string input, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result)
{
try {
result = Parse (input, formatProvider, styles);
return true;
} catch {
result = MinValue;
return false;
}
}
public static bool TryParseExact (string input, string format, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result)
{
try {
result = ParseExact (input, format, formatProvider, styles);
return true;
} catch {
result = MinValue;
return false;
}
}
public static bool TryParseExact (string input, string[] formats, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result)
{
try {
result = ParseExact (input, formats, formatProvider, styles);
return true;
} catch {
result = MinValue;
return false;
}
}
public DateTime Date {
get { return DateTime.SpecifyKind (dt.Date, DateTimeKind.Unspecified); }
}
public DateTime DateTime {
get { return DateTime.SpecifyKind (dt, DateTimeKind.Unspecified); }
}
public int Day {
get { return dt.Day; }
}
public DayOfWeek DayOfWeek {
get { return dt.DayOfWeek; }
}
public int DayOfYear {
get { return dt.DayOfYear; }
}
public int Hour {
get { return dt.Hour; }
}
public DateTime LocalDateTime {
get { return UtcDateTime.ToLocalTime (); }
}
public int Millisecond {
get { return dt.Millisecond; }
}
public int Minute {
get { return dt.Minute; }
}
public int Month {
get { return dt.Month; }
}
public static DateTimeOffset Now {
get { return new DateTimeOffset (DateTime.Now);}
}
public TimeSpan Offset {
get { return utc_offset; }
}
public int Second {
get { return dt.Second; }
}
public long Ticks {
get { return dt.Ticks; }
}
public TimeSpan TimeOfDay {
get { return dt.TimeOfDay; }
}
public DateTime UtcDateTime {
get { return DateTime.SpecifyKind (dt - utc_offset, DateTimeKind.Utc); }
}
public static DateTimeOffset UtcNow {
get { return new DateTimeOffset (DateTime.UtcNow); }
}
public long UtcTicks {
get { return UtcDateTime.Ticks; }
}
public int Year {
get { return dt.Year; }
}
}
}