[corlib] Fix 44255: Inconsistent results in the serialization of TimeZoneInfo. ...
[mono.git] / mcs / class / corlib / System / TimeZoneInfo.cs
index f8e54b7fb85cbcd14606b9bc3db77ce7ddbfed80..25d9e9a39becbcd5e395d7c057ecaf11afc3d312 100644 (file)
@@ -149,10 +149,10 @@ namespace System
                        return true;
                }
 
-#if !MOBILE || MOBILE_STATIC
+#if !MONODROID && !MONOTOUCH && !XAMMAC
                static TimeZoneInfo CreateLocal ()
                {
-#if !MOBILE_STATIC
+#if WIN_PLATFORM
                        if (IsWindows && LocalZoneKey != null) {
                                string name = (string)LocalZoneKey.GetValue ("TimeZoneKeyName");
                                if (name == null)
@@ -160,6 +160,8 @@ namespace System
                                name = TrimSpecial (name);
                                if (name != null)
                                        return TimeZoneInfo.FindSystemTimeZoneById (name);
+                       } else if (IsWindows) {
+                               return GetLocalTimeZoneInfoWinRTFallback ();
                        }
 #endif
 
@@ -204,7 +206,7 @@ namespace System
 
                static void GetSystemTimeZonesCore (List<TimeZoneInfo> systemTimeZones)
                {
-#if !MOBILE_STATIC
+#if WIN_PLATFORM
                        if (TimeZoneKey != null) {
                                foreach (string id in TimeZoneKey.GetSubKeyNames ()) {
                                        try {
@@ -212,6 +214,9 @@ namespace System
                                        } catch {}
                                }
 
+                               return;
+                       } else if (IsWindows) {
+                               systemTimeZones.AddRange (GetSystemTimeZonesWinRTFallback ());
                                return;
                        }
 #endif
@@ -237,7 +242,7 @@ namespace System
                        throw new NotImplementedException ("This method is not implemented for this platform");
 #endif
                }
-#endif
+#endif // !MONODROID && !MONOTOUCH && !XAMMAC
 
                string standardDisplayName;
                public string StandardName {
@@ -273,7 +278,7 @@ namespace System
 #endif
                private AdjustmentRule [] adjustmentRules;
 
-#if !MOBILE || MOBILE_STATIC
+#if (!MOBILE || !FULL_AOT_DESKTOP || WIN_PLATFORM) && !XAMMAC_4_5
                /// <summary>
                /// Determine whether windows of not (taken Stephane Delcroix's code)
                /// </summary>
@@ -300,8 +305,8 @@ namespace System
                        
                        return str.Substring (Istart, Iend-Istart+1);
                }
-               
-#if !MOBILE_STATIC
+
+#if !FULL_AOT_DESKTOP || WIN_PLATFORM
                static RegistryKey timeZoneKey;
                static RegistryKey TimeZoneKey {
                        get {
@@ -310,9 +315,13 @@ namespace System
                                if (!IsWindows)
                                        return null;
                                
-                               return timeZoneKey = Registry.LocalMachine.OpenSubKey (
-                                       "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
-                                       false);
+                               try {
+                                       return timeZoneKey = Registry.LocalMachine.OpenSubKey (
+                                               "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
+                                               false);
+                               } catch {
+                                       return null;
+                               }
                        }
                }
                
@@ -325,12 +334,16 @@ namespace System
                                if (!IsWindows)
                                        return null;
                                
-                               return localZoneKey = Registry.LocalMachine.OpenSubKey (
-                                       "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation", false);
+                               try {
+                                       return localZoneKey = Registry.LocalMachine.OpenSubKey (
+                                               "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation", false);
+                               } catch {
+                                       return null;
+                               }
                        }
                }
 #endif
-#endif
+#endif // !MOBILE || !FULL_AOT_DESKTOP || WIN_PLATFORM
 
                private static bool TryAddTicks (DateTime date, long ticks, out DateTime result, DateTimeKind kind = DateTimeKind.Unspecified)
                {
@@ -538,7 +551,7 @@ namespace System
                        //FIXME: this method should check for cached values in systemTimeZones
                        if (id == null)
                                throw new ArgumentNullException ("id");
-#if !MOBILE
+#if WIN_PLATFORM
                        if (TimeZoneKey != null)
                        {
                                if (id == "Coordinated Universal Time")
@@ -547,6 +560,8 @@ namespace System
                                if (key == null)
                                        throw new TimeZoneNotFoundException ();
                                return FromRegistryKey(id, key);
+                       } else if (IsWindows) {
+                               return FindSystemTimeZoneByIdWinRTFallback (id);
                        }
 #endif
                        // Local requires special logic that already exists in the Local property (bug #326)
@@ -559,16 +574,22 @@ namespace System
 #if LIBC
                private static TimeZoneInfo FindSystemTimeZoneByFileName (string id, string filepath)
                {
-                       if (!File.Exists (filepath))
-                               throw new TimeZoneNotFoundException ();
-
-                       using (FileStream stream = File.OpenRead (filepath)) {
+                       FileStream stream = null;
+                       try {
+                               stream = File.OpenRead (filepath);      
+                       } catch (Exception ex) {
+                               throw new TimeZoneNotFoundException ("Couldn't read time zone file " + filepath, ex);
+                       }
+                       try {
                                return BuildFromStream (id, stream);
+                       } finally {
+                               if (stream != null)
+                                       stream.Dispose();
                        }
                }
 #endif
 
-#if !MOBILE
+#if WIN_PLATFORM
                private static TimeZoneInfo FromRegistryKey (string id, RegistryKey key)
                {
                        byte [] reg_tzi = (byte []) key.GetValue ("TZI");
@@ -603,7 +624,7 @@ namespace System
                        else
                                ParseRegTzi(adjustmentRules, 1, 9999, reg_tzi);
 
-                       return CreateCustomTimeZone (id, baseUtcOffset, display_name, standard_name, daylight_name, ValidateRules (adjustmentRules).ToArray ());
+                       return CreateCustomTimeZone (id, baseUtcOffset, display_name, standard_name, daylight_name, ValidateRules (adjustmentRules));
                }
 
                private static void ParseRegTzi (List<AdjustmentRule> adjustmentRules, int start_year, int end_year, byte [] buffer)
@@ -811,7 +832,7 @@ namespace System
                                        return tz.BaseUtcOffset;
                        }
 
-                       if (tzRule != null && tz.IsInDST (tzRule, stdUtcDateTime)) {
+                       if (tzRule != null && tz.IsInDST (tzRule, dateTime)) {
                                // Replicate what .NET does when given a time which falls into the hour which is lost when
                                // DST starts. isDST should always be true but the offset should be BaseUtcOffset without the
                                // DST delta while in that hour.
@@ -868,7 +889,7 @@ namespace System
                        AdjustmentRule rule = GetApplicableRule (dateTime);
                        if (rule != null) {
                                DateTime tpoint = TransitionPoint (rule.DaylightTransitionEnd, dateTime.Year);
-                               if (dateTime > tpoint - rule.DaylightDelta  && dateTime <= tpoint)
+                               if (dateTime > tpoint - rule.DaylightDelta && dateTime <= tpoint)
                                        return true;
                        }
                                
@@ -898,7 +919,6 @@ namespace System
                                DST_start -= BaseUtcOffset;
                                DST_end -= (BaseUtcOffset + rule.DaylightDelta);
                        }
-
                        return (dateTime >= DST_start && dateTime < DST_end);
                }
                
@@ -1184,31 +1204,16 @@ namespace System
                                        return false;
                        }
 
-                       var inDelta = false;
-                       for (var i =  transitions.Count - 1; i >= 0; i--) {
-                               var pair = transitions [i];
-                               DateTime ttime = pair.Key;
-                               TimeType ttype = pair.Value;
-
-                               var delta =  new TimeSpan (0, 0, ttype.Offset) - BaseUtcOffset;
-
-                               if ((ttime + delta) > date) {
-                                       inDelta = ttime <= date;
-                                       continue;
-                               }
-
-                               offset =  new TimeSpan (0, 0, ttype.Offset);
-                               if (inDelta) {
-                                       // Replicate what .NET does when given a time which falls into the hour which is lost when
-                                       // DST starts. isDST should be true but the offset should be the non-DST offset.
-                                       isDst = transitions [i - 1].Value.IsDst;
-                               } else {
-                                       isDst = ttype.IsDst;
+                       AdjustmentRule current = GetApplicableRule(date);
+                       if (current != null) {
+                               DateTime tStart = TransitionPoint(current.DaylightTransitionStart, date.Year);
+                               DateTime tEnd = TransitionPoint(current.DaylightTransitionEnd, date.Year);
+                               if ((date >= tStart) && (date <= tEnd)) {
+                                       offset = baseUtcOffset + current.DaylightDelta; 
+                                       isDst = true;
+                                       return true;
                                }
-
-                               return true;
                        }
-
                        return false;
                }
 
@@ -1226,8 +1231,11 @@ namespace System
                        return new DateTime (year, transition.Month, day) + transition.TimeOfDay.TimeOfDay;
                }
 
-               static List<AdjustmentRule> ValidateRules (List<AdjustmentRule> adjustmentRules)
+               static AdjustmentRule[] ValidateRules (List<AdjustmentRule> adjustmentRules)
                {
+                       if (adjustmentRules == null || adjustmentRules.Count == 0)
+                               return null;
+
                        AdjustmentRule prev = null;
                        foreach (AdjustmentRule current in adjustmentRules.ToArray ()) {
                                if (prev != null && prev.DateEnd > current.DateStart) {
@@ -1235,7 +1243,7 @@ namespace System
                                }
                                prev = current;
                        }
-                       return adjustmentRules;
+                       return adjustmentRules.ToArray ();
                }
 
 #if LIBC || MONOTOUCH
@@ -1399,13 +1407,13 @@ namespace System
                                }
                                tz = CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName);
                        } else {
-                               tz = CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName, daylightDisplayName, ValidateRules (adjustmentRules).ToArray ());
+                               tz = CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName, daylightDisplayName, ValidateRules (adjustmentRules));
                        }
 
                        if (storeTransition && transitions.Count > 0) {
                                tz.transitions = transitions;
-                               tz.supportsDaylightSavingTime = true;
                        }
+                       tz.supportsDaylightSavingTime = adjustmentRules.Count > 0;
 
                        return tz;
                }
@@ -1498,7 +1506,7 @@ namespace System
 
                        if (zone.IsAmbiguousTime (time)) {
                                isAmbiguousLocalDst = true;
-                               return baseOffset;
+//                             return baseOffset;
                        }
 
                        return zone.GetUtcOffset (time, out isDaylightSavings);