[corlib] Removed referencesource duplicated code.
[mono.git] / mcs / class / corlib / System / TimeZoneInfo.cs
index a6a3c1a106ff111f699df14b2bc609b26202b32a..77ddf5b9c77129dc51fa4e9964e9e1c9c94a6517 100644 (file)
@@ -34,6 +34,7 @@ using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Runtime.Serialization;
 using System.Text;
+using System.Globalization;
 
 #if LIBC || MONODROID
 using System.IO;
@@ -108,12 +109,16 @@ namespace System
                                return BuildFromStream ("Local", stream);
                        }
 #else
+#if !NET_2_1
                        if (IsWindows && LocalZoneKey != null) {
                                string name = (string)LocalZoneKey.GetValue ("TimeZoneKeyName");
+                               if (name == null)
+                                       name = (string)LocalZoneKey.GetValue ("StandardName"); // windows xp
                                name = TrimSpecial (name);
                                if (name != null)
                                        return TimeZoneInfo.FindSystemTimeZoneById (name);
                        }
+#endif
 
                        var tz = Environment.GetEnvironmentVariable ("TZ");
                        if (tz != null) {
@@ -189,6 +194,8 @@ namespace System
                /// </summary>
                private static string TrimSpecial (string str)
                {
+                       if (str == null)
+                               return str;
                        var Istart = 0;
                        while (Istart < str.Length && !char.IsLetterOrDigit(str[Istart])) Istart++;
                        var Iend = str.Length - 1;
@@ -273,17 +280,13 @@ namespace System
                {
                        if (destinationTimeZone == null) 
                                throw new ArgumentNullException("destinationTimeZone");
-               
+
                        var utcDateTime = dateTimeOffset.UtcDateTime;
-                       AdjustmentRule rule = destinationTimeZone.GetApplicableRule (utcDateTime);
-               
-                       if (rule != null && destinationTimeZone.IsDaylightSavingTime(utcDateTime)) {
-                               var offset = destinationTimeZone.BaseUtcOffset + rule.DaylightDelta;
-                               return new DateTimeOffset(DateTime.SpecifyKind(utcDateTime, DateTimeKind.Unspecified) + offset, offset);
-                       }
-                       else {
-                               return new DateTimeOffset(DateTime.SpecifyKind(utcDateTime, DateTimeKind.Unspecified) + destinationTimeZone.BaseUtcOffset, destinationTimeZone.BaseUtcOffset);
-                       }
+
+                       bool isDst;
+                       var utcOffset =  destinationTimeZone.GetUtcOffset(utcDateTime, out isDst);
+
+                       return new DateTimeOffset(DateTime.SpecifyKind(utcDateTime, DateTimeKind.Unspecified) + utcOffset, utcOffset);
                }
 
                public static DateTime ConvertTimeBySystemTimeZoneId (DateTime dateTime, string destinationTimeZoneId)
@@ -308,19 +311,12 @@ namespace System
 
                        if (this == TimeZoneInfo.Utc)
                                return DateTime.SpecifyKind (dateTime, DateTimeKind.Utc);
-                       
-                       //FIXME: do not rely on DateTime implementation !
-                       if (this == TimeZoneInfo.Local) 
-                       {
-                               return dateTime.ToLocalTime ();
-                       }
 
+                       var utcOffset = GetUtcOffset (dateTime);
 
-                       AdjustmentRule rule = GetApplicableRule (dateTime);
-                       if (rule != null && IsDaylightSavingTime (DateTime.SpecifyKind (dateTime, DateTimeKind.Utc)))
-                               return DateTime.SpecifyKind (dateTime + BaseUtcOffset + rule.DaylightDelta , DateTimeKind.Unspecified);
-                       else
-                               return DateTime.SpecifyKind (dateTime + BaseUtcOffset, DateTimeKind.Unspecified);
+                       var kind = (this == TimeZoneInfo.Local)? DateTimeKind.Local : DateTimeKind.Unspecified;
+
+                       return DateTime.SpecifyKind (dateTime + utcOffset, kind);
                }
 
                public static DateTime ConvertTimeFromUtc (DateTime dateTime, TimeZoneInfo destinationTimeZone)
@@ -339,32 +335,45 @@ namespace System
                        return ConvertTimeToUtc (dateTime, TimeZoneInfo.Local);
                }
 
+               static internal DateTime ConvertTimeToUtc(DateTime dateTime, TimeZoneInfoOptions flags)
+               {
+                       return ConvertTimeToUtc (dateTime, TimeZoneInfo.Local, flags);
+               }
+
                public static DateTime ConvertTimeToUtc (DateTime dateTime, TimeZoneInfo sourceTimeZone)
                {
-                       if (sourceTimeZone == null)
-                               throw new ArgumentNullException ("sourceTimeZone");
+                       return ConvertTimeToUtc (dateTime, sourceTimeZone, TimeZoneInfoOptions.None);
+               }
 
-                       if (dateTime.Kind == DateTimeKind.Utc && sourceTimeZone != TimeZoneInfo.Utc)
-                               throw new ArgumentException ("Kind property of dateTime is Utc but the sourceTimeZone does not equal TimeZoneInfo.Utc");
+               static DateTime ConvertTimeToUtc (DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfoOptions flags)
+               {
+                       if ((flags & TimeZoneInfoOptions.NoThrowOnInvalidTime) == 0) {
+                               if (sourceTimeZone == null)
+                                       throw new ArgumentNullException ("sourceTimeZone");
 
-                       if (dateTime.Kind == DateTimeKind.Local && sourceTimeZone != TimeZoneInfo.Local)
-                               throw new ArgumentException ("Kind property of dateTime is Local but the sourceTimeZone does not equal TimeZoneInfo.Local");
+                               if (dateTime.Kind == DateTimeKind.Utc && sourceTimeZone != TimeZoneInfo.Utc)
+                                       throw new ArgumentException ("Kind property of dateTime is Utc but the sourceTimeZone does not equal TimeZoneInfo.Utc");
 
-                       if (sourceTimeZone.IsInvalidTime (dateTime))
-                               throw new ArgumentException ("dateTime parameter is an invalid time");
+                               if (dateTime.Kind == DateTimeKind.Local && sourceTimeZone != TimeZoneInfo.Local)
+                                       throw new ArgumentException ("Kind property of dateTime is Local but the sourceTimeZone does not equal TimeZoneInfo.Local");
+
+                               if (sourceTimeZone.IsInvalidTime (dateTime))
+                                       throw new ArgumentException ("dateTime parameter is an invalid time");
+                       }
 
                        if (dateTime.Kind == DateTimeKind.Utc)
                                return dateTime;
 
-                       if (sourceTimeZone.IsAmbiguousTime (dateTime) || !sourceTimeZone.IsDaylightSavingTime (dateTime))
-                               return DateTime.SpecifyKind (dateTime - sourceTimeZone.BaseUtcOffset, DateTimeKind.Utc);
-                       else {
-                               AdjustmentRule rule = sourceTimeZone.GetApplicableRule (dateTime);
-                               if (rule != null)
-                                       return DateTime.SpecifyKind (dateTime - sourceTimeZone.BaseUtcOffset - rule.DaylightDelta, DateTimeKind.Utc);
-                               else
-                                       return DateTime.SpecifyKind (dateTime - sourceTimeZone.BaseUtcOffset, DateTimeKind.Utc);
-                       }
+                       bool isDst;
+                       var utcOffset = sourceTimeZone.GetUtcOffset (dateTime, out isDst);
+
+                       return DateTime.SpecifyKind (dateTime - utcOffset, DateTimeKind.Utc);
+               }
+
+               static internal TimeSpan GetDateTimeNowUtcOffsetFromUtc(DateTime time, out Boolean isAmbiguousLocalDst)
+               {
+                       bool isDaylightSavings;
+                       return GetUtcOffsetFromUtc(time, TimeZoneInfo.Local, out isDaylightSavings, out isAmbiguousLocalDst);
                }
 
                public static TimeZoneInfo CreateCustomTimeZone (string id, TimeSpan baseUtcOffset, string displayName, string standardDisplayName) 
@@ -403,6 +412,8 @@ namespace System
 #if !NET_2_1
                        if (TimeZoneKey != null)
                        {
+                               if (id == "Coordinated Universal Time")
+                                       id = "UTC"; //windows xp exception for "StandardName" property
                                RegistryKey key = TimeZoneKey.OpenSubKey (id, false);
                                if (key == null)
                                        throw new TimeZoneNotFoundException ();
@@ -694,7 +705,7 @@ namespace System
                                tz = TimeZoneInfo.Local;
 
                        bool isTzDst;
-                       var tzOffset = GetUtcOffset (dateTime, tz, out isTzDst);
+                       var tzOffset = GetUtcOffsetHelper (dateTime, tz, out isTzDst);
 
                        if (tz == this) {
                                isDST = isTzDst;
@@ -707,10 +718,11 @@ namespace System
 
                        var utcDateTime = new DateTime (utcTicks, DateTimeKind.Utc);
 
-                       return GetUtcOffset (utcDateTime, this, out isDST);
+                       return GetUtcOffsetHelper (utcDateTime, this, out isDST);
                }
 
-               private static TimeSpan GetUtcOffset (DateTime dateTime, TimeZoneInfo tz, out bool isDST)
+               // This is an helper method used by the method above, do not use this on its own.
+               private static TimeSpan GetUtcOffsetHelper (DateTime dateTime, TimeZoneInfo tz, out bool isDST)
                {
                        if (dateTime.Kind == DateTimeKind.Local && tz != TimeZoneInfo.Local)
                                throw new Exception ();
@@ -851,6 +863,11 @@ namespace System
                        return isDst;
                }
 
+               internal bool IsDaylightSavingTime (DateTime dateTime, TimeZoneInfoOptions flags)
+               {
+                       return IsDaylightSavingTime (dateTime);
+               }
+
                public bool IsDaylightSavingTime (DateTimeOffset dateTimeOffset)
                {
                        throw new NotImplementedException ();
@@ -869,7 +886,7 @@ namespace System
                                if (dateTime >= tpoint && dateTime < tpoint + rule.DaylightDelta)
                                        return true;
                        }
-                               
+
                        return false;
                }
 
@@ -1000,7 +1017,7 @@ namespace System
 
                private AdjustmentRule GetApplicableRule (DateTime dateTime)
                {
-                       //Transitions are always in standard time
+                       //Applicable rules are in standard time
                        DateTime date = dateTime;
 
                        if (dateTime.Kind == DateTimeKind.Local && this != TimeZoneInfo.Local)
@@ -1031,14 +1048,24 @@ namespace System
                        if (transitions == null)
                                return false;
 
-                       //Transitions are always in standard time
+                       //Transitions are in UTC
                        DateTime date = dateTime;
 
-                       if (dateTime.Kind == DateTimeKind.Local && this != TimeZoneInfo.Local)
-                               date = date.ToUniversalTime () + BaseUtcOffset;
+                       if (dateTime.Kind == DateTimeKind.Local && this != TimeZoneInfo.Local) {
+                               var ticks = date.ToUniversalTime ().Ticks + BaseUtcOffset.Ticks;
+                               if (ticks < DateTime.MinValue.Ticks || ticks > DateTime.MaxValue.Ticks)
+                                       return false;
 
-                       if (dateTime.Kind == DateTimeKind.Utc && this != TimeZoneInfo.Utc)
-                               date = date + BaseUtcOffset;
+                               date = new DateTime (ticks, DateTimeKind.Utc);
+                       }
+
+                       if (dateTime.Kind != DateTimeKind.Utc) {
+                               var ticks = date.Ticks - BaseUtcOffset.Ticks;
+                               if (ticks < DateTime.MinValue.Ticks || ticks > DateTime.MaxValue.Ticks)
+                                       return false;
+
+                               date = new DateTime (ticks, DateTimeKind.Utc);
+                       }
 
                        for (var i =  transitions.Count - 1; i >= 0; i--) {
                                var pair = transitions [i];
@@ -1270,6 +1297,35 @@ namespace System
                        DateTime date_time = new DateTime (1970, 1, 1);
                        return date_time.AddSeconds (unix_time);
                }
+
+#region reference sources
+               // Shortcut for TimeZoneInfo.Local.GetUtcOffset
+               internal static TimeSpan GetLocalUtcOffset(DateTime dateTime, TimeZoneInfoOptions flags)
+               {
+                       bool dst;
+                       return Local.GetUtcOffset (dateTime, out dst);
+               }
+
+               internal TimeSpan GetUtcOffset(DateTime dateTime, TimeZoneInfoOptions flags)
+               {
+                       bool dst;
+                       return GetUtcOffset (dateTime, out dst);
+               }
+
+               static internal TimeSpan GetUtcOffsetFromUtc (DateTime time, TimeZoneInfo zone, out Boolean isDaylightSavings, out Boolean isAmbiguousLocalDst)
+               {
+                       isDaylightSavings = false;
+                       isAmbiguousLocalDst = false;
+                       TimeSpan baseOffset = zone.BaseUtcOffset;
+
+                       if (zone.IsAmbiguousTime (time)) {
+                               isAmbiguousLocalDst = true;
+                               return baseOffset;
+                       }
+
+                       return zone.GetUtcOffset (time, out isDaylightSavings);
+               }
+#endregion
        }
 
        struct TimeType {