Merge pull request #487 from mayerwin/patch-1
[mono.git] / mcs / class / System.Core / System / TimeZoneInfo.cs
index ce6accc38728a0bac7893e268f032489fe638c02..3bfcd0c204c62299d4b5d5f0b2e7f4144e032721 100644 (file)
@@ -4,6 +4,8 @@
  * Author(s)
  *     Stephane Delcroix <stephane@delcroix.org>
  *
+ * Copyright 2011 Xamarin Inc.
+ *
  * 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
  */
 
 using System;
+using System.Runtime.CompilerServices;
+
+#if !INSIDE_CORLIB && (NET_4_0 || MOONLIGHT || MOBILE)
+
+[assembly:TypeForwardedTo (typeof(TimeZoneInfo))]
+
+#elif (INSIDE_CORLIB && (NET_4_0 || MOONLIGHT || MOBILE)) || (!INSIDE_CORLIB && (NET_3_5 && !NET_4_0 && !MOBILE))
+
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Runtime.Serialization;
 using System.Text;
 
-#if LIBC
+#if LIBC || MONODROID
 using System.IO;
 using Mono;
 #endif
 
+using Microsoft.Win32;
+
 namespace System
 {
+#if NET_4_0
+       [TypeForwardedFrom (Consts.AssemblySystemCore_3_5)]
+#elif MOONLIGHT || MOBILE
+       [TypeForwardedFrom (Consts.AssemblySystem_Core)]
+#endif
        [SerializableAttribute]
        public sealed partial class TimeZoneInfo : IEquatable<TimeZoneInfo>, ISerializable, IDeserializationCallback
        {
@@ -48,9 +65,9 @@ namespace System
                string daylightDisplayName;
                public string DaylightName {
                        get { 
-                               if (disableDaylightSavingTime)
-                                       return String.Empty;
-                               return daylightDisplayName; 
+                               return supportsDaylightSavingTime
+                                       ? daylightDisplayName
+                                       : string.Empty;
                        }
                }
 
@@ -68,7 +85,13 @@ namespace System
                public static TimeZoneInfo Local {
                        get { 
                                if (local == null) {
-#if LIBC
+#if MONODROID
+                                       local = ZoneInfoDB.Default;
+#elif MONOTOUCH
+                                       using (Stream stream = GetMonoTouchDefault ()) {
+                                               local = BuildFromStream ("Local", stream);
+                                       }
+#elif LIBC
                                        try {
                                                local = FindSystemTimeZoneByFileName ("Local", "/etc/localtime");       
                                        } catch {
@@ -79,7 +102,15 @@ namespace System
                                                }
                                        }
 #else
-                                       throw new TimeZoneNotFoundException ();
+                                       if (IsWindows && LocalZoneKey != null) {
+                                               string name = (string)LocalZoneKey.GetValue ("TimeZoneKeyName");
+                                               name = TrimSpecial (name);
+                                               if (name != null)
+                                                       local = TimeZoneInfo.FindSystemTimeZoneById (name);
+                                       }
+                                       
+                                       if (local == null)
+                                               throw new TimeZoneNotFoundException ();
 #endif
                                }
                                return local;
@@ -91,9 +122,9 @@ namespace System
                        get { return standardDisplayName; }
                }
 
-               bool disableDaylightSavingTime;
+               bool supportsDaylightSavingTime;
                public bool SupportsDaylightSavingTime {
-                       get  { return !disableDaylightSavingTime; }
+                       get  { return supportsDaylightSavingTime; }
                }
 
                static TimeZoneInfo utc;
@@ -105,7 +136,7 @@ namespace System
                        }
                }
 #if LIBC
-               static string timeZoneDirectory = null;
+               static string timeZoneDirectory;
                static string TimeZoneDirectory {
                        get {
                                if (timeZoneDirectory == null)
@@ -120,6 +151,60 @@ namespace System
 #endif
                private AdjustmentRule [] adjustmentRules;
 
+#if !NET_2_1
+               /// <summary>
+               /// Determine whether windows of not (taken Stephane Delcroix's code)
+               /// </summary>
+               private static bool IsWindows
+               {
+                       get {
+                               int platform = (int) Environment.OSVersion.Platform;
+                               return ((platform != 4) && (platform != 6) && (platform != 128));
+                       }
+               }
+               
+               /// <summary>
+               /// Needed to trim misc garbage in MS registry keys
+               /// </summary>
+               private static string TrimSpecial (string str)
+               {
+                       var Istart = 0;
+                       while (Istart < str.Length && !char.IsLetterOrDigit(str[Istart])) Istart++;
+                       var Iend = str.Length - 1;
+                       while (Iend > Istart && !char.IsLetterOrDigit(str[Iend])) Iend--;
+                       
+                       return str.Substring (Istart, Iend-Istart+1);
+               }
+               
+               static RegistryKey timeZoneKey;
+               static RegistryKey TimeZoneKey {
+                       get {
+                               if (timeZoneKey != null)
+                                       return timeZoneKey;
+                               if (!IsWindows)
+                                       return null;
+                               
+                               return timeZoneKey = Registry.LocalMachine.OpenSubKey (
+                                       "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
+                                       false);
+                       }
+               }
+               
+               static RegistryKey localZoneKey;
+               static RegistryKey LocalZoneKey {
+                       get {
+                               if (localZoneKey != null)
+                                       return localZoneKey;
+                               
+                               if (!IsWindows)
+                                       return null;
+                               
+                               return localZoneKey = Registry.LocalMachine.OpenSubKey (
+                                       "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation", false);
+                       }
+               }
+#endif
+
                public static void ClearCachedData ()
                {
                        local = null;
@@ -135,10 +220,10 @@ namespace System
                public static DateTime ConvertTime (DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone)
                {
                        if (dateTime.Kind == DateTimeKind.Local && sourceTimeZone != TimeZoneInfo.Local)
-                               throw new ArgumentException ("Kind propery of dateTime is Local but the sourceTimeZone does not equal 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 propery of dateTime is Utc but the sourceTimeZone does not equal 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");
@@ -161,9 +246,21 @@ namespace System
 
                }
 
-               public static DateTimeOffset ConvertTime (DateTimeOffset dateTimeOffset, TimeZoneInfo destinationTimeZone)
+               public static DateTimeOffset ConvertTime(DateTimeOffset dateTimeOffset, TimeZoneInfo destinationTimeZone) 
                {
-                       throw new NotImplementedException ();
+                       if (destinationTimeZone == null) 
+                               throw new ArgumentNullException("destinationTimeZone");
+               
+                       var utcDateTime = dateTimeOffset.UtcDateTime;
+                       AdjustmentRule rule = 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);
+                       }
                }
 
                public static DateTime ConvertTimeBySystemTimeZoneId (DateTime dateTime, string destinationTimeZoneId)
@@ -195,7 +292,7 @@ namespace System
 
                        AdjustmentRule rule = GetApplicableRule (dateTime);
                
-                       if (IsDaylightSavingTime (DateTime.SpecifyKind (dateTime, DateTimeKind.Utc)))
+                       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);
@@ -224,10 +321,10 @@ namespace System
                                throw new ArgumentNullException ("sourceTimeZone");
 
                        if (dateTime.Kind == DateTimeKind.Utc && sourceTimeZone != TimeZoneInfo.Utc)
-                               throw new ArgumentException ("Kind propery of dateTime is Utc but the sourceTimeZone does not equal TimeZoneInfo.Utc");
+                               throw new ArgumentException ("Kind property of dateTime is Utc but the sourceTimeZone does not equal TimeZoneInfo.Utc");
 
                        if (dateTime.Kind == DateTimeKind.Local && sourceTimeZone != TimeZoneInfo.Local)
-                               throw new ArgumentException ("Kind propery of dateTime is Local but the sourceTimeZone does not equal 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");
@@ -245,7 +342,10 @@ namespace System
                                return DateTime.SpecifyKind (dateTime - sourceTimeZone.BaseUtcOffset, DateTimeKind.Utc);
                        else {
                                AdjustmentRule rule = sourceTimeZone.GetApplicableRule (dateTime);
-                               return DateTime.SpecifyKind (dateTime - sourceTimeZone.BaseUtcOffset - rule.DaylightDelta, DateTimeKind.Utc);
+                               if (rule != null)
+                                       return DateTime.SpecifyKind (dateTime - sourceTimeZone.BaseUtcOffset - rule.DaylightDelta, DateTimeKind.Utc);
+                               else
+                                       return DateTime.SpecifyKind (dateTime - sourceTimeZone.BaseUtcOffset, DateTimeKind.Utc);
                        }
                }
 
@@ -264,6 +364,13 @@ namespace System
                        return new TimeZoneInfo (id, baseUtcOffset, displayName, standardDisplayName, daylightDisplayName, adjustmentRules, disableDaylightSavingTime);
                }
 
+#if NET_4_5
+               public override bool Equals (object obj)
+               {
+                       return Equals (obj as TimeZoneInfo);
+               }
+#endif
+
                public bool Equals (TimeZoneInfo other)
                {
                        if (other == null)
@@ -277,27 +384,56 @@ namespace System
                        //FIXME: this method should check for cached values in systemTimeZones
                        if (id == null)
                                throw new ArgumentNullException ("id");
-#if LIBC       
+#if !NET_2_1
+                       if (TimeZoneKey != null)
+                       {
+                               RegistryKey key = TimeZoneKey.OpenSubKey (id, false);
+                               if (key == null)
+                                       throw new TimeZoneNotFoundException ();
+                               return FromRegistryKey(id, key);
+                       }
+#endif
+#if MONODROID
+                       var timeZoneInfo = ZoneInfoDB.GetTimeZone (id);
+                       if (timeZoneInfo == null)
+                               throw new TimeZoneNotFoundException ();
+                       return timeZoneInfo;
+#else
+                       // Local requires special logic that already exists in the Local property (bug #326)
+                       if (id == "Local")
+                               return Local;
+#if MONOTOUCH
+                       using (Stream stream = GetMonoTouchData (id)) {
+                               return BuildFromStream (id, stream);
+                       }
+#elif LIBC
                        string filepath = Path.Combine (TimeZoneDirectory, id);
                        return FindSystemTimeZoneByFileName (id, filepath);
 #else
                        throw new NotImplementedException ();
+#endif
 #endif
                }
 
 #if LIBC
-               const int BUFFER_SIZE = 16384; //Big enough for any tz file (on Oct 2008, all tz files are under 10k)
                private static TimeZoneInfo FindSystemTimeZoneByFileName (string id, string filepath)
                {
                        if (!File.Exists (filepath))
                                throw new TimeZoneNotFoundException ();
 
-                       byte [] buffer = new byte [BUFFER_SIZE];
-                       int length;
                        using (FileStream stream = File.OpenRead (filepath)) {
-                               length = stream.Read (buffer, 0, BUFFER_SIZE);
+                               return BuildFromStream (id, stream);
                        }
-
+               }
+#endif
+#if LIBC || MONOTOUCH
+               const int BUFFER_SIZE = 16384; //Big enough for any tz file (on Oct 2008, all tz files are under 10k)
+               
+               private static TimeZoneInfo BuildFromStream (string id, Stream stream) 
+               {
+                       byte [] buffer = new byte [BUFFER_SIZE];
+                       int length = stream.Read (buffer, 0, BUFFER_SIZE);
+                       
                        if (!ValidTZFile (buffer, length))
                                throw new InvalidTimeZoneException ("TZ file too big for the buffer");
 
@@ -309,6 +445,112 @@ namespace System
                }
 #endif
 
+#if !NET_2_1
+               private static TimeZoneInfo FromRegistryKey (string id, RegistryKey key)
+               {
+                       byte [] reg_tzi = (byte []) key.GetValue ("TZI");
+
+                       if (reg_tzi == null)
+                               throw new InvalidTimeZoneException ();
+
+                       int bias = BitConverter.ToInt32 (reg_tzi, 0);
+                       TimeSpan baseUtcOffset = new TimeSpan (0, -bias, 0);
+
+                       string display_name = (string) key.GetValue ("Display");
+                       string standard_name = (string) key.GetValue ("Std");
+                       string daylight_name = (string) key.GetValue ("Dlt");
+
+                       List<AdjustmentRule> adjustmentRules = new List<AdjustmentRule> ();
+
+                       RegistryKey dst_key = key.OpenSubKey ("Dynamic DST", false);
+                       if (dst_key != null) {
+                               int first_year = (int) dst_key.GetValue ("FirstEntry");
+                               int last_year = (int) dst_key.GetValue ("LastEntry");
+                               int year;
+
+                               for (year=first_year; year<=last_year; year++) {
+                                       byte [] dst_tzi = (byte []) dst_key.GetValue (year.ToString ());
+                                       if (dst_tzi != null) {
+                                               int start_year = year == first_year ? 1 : year;
+                                               int end_year = year == last_year ? 9999 : year;
+                                               ParseRegTzi(adjustmentRules, start_year, end_year, dst_tzi);
+                                       }
+                               }
+                       }
+                       else
+                               ParseRegTzi(adjustmentRules, 1, 9999, reg_tzi);
+
+                       return CreateCustomTimeZone (id, baseUtcOffset, display_name, standard_name, daylight_name, ValidateRules (adjustmentRules).ToArray ());
+               }
+
+               private static void ParseRegTzi (List<AdjustmentRule> adjustmentRules, int start_year, int end_year, byte [] buffer)
+               {
+                       //int standard_bias = BitConverter.ToInt32 (buffer, 4); /* not sure how to handle this */
+                       int daylight_bias = BitConverter.ToInt32 (buffer, 8);
+
+                       int standard_year = BitConverter.ToInt16 (buffer, 12);
+                       int standard_month = BitConverter.ToInt16 (buffer, 14);
+                       int standard_dayofweek = BitConverter.ToInt16 (buffer, 16);
+                       int standard_day = BitConverter.ToInt16 (buffer, 18);
+                       int standard_hour = BitConverter.ToInt16 (buffer, 20);
+                       int standard_minute = BitConverter.ToInt16 (buffer, 22);
+                       int standard_second = BitConverter.ToInt16 (buffer, 24);
+                       int standard_millisecond = BitConverter.ToInt16 (buffer, 26);
+
+                       int daylight_year = BitConverter.ToInt16 (buffer, 28);
+                       int daylight_month = BitConverter.ToInt16 (buffer, 30);
+                       int daylight_dayofweek = BitConverter.ToInt16 (buffer, 32);
+                       int daylight_day = BitConverter.ToInt16 (buffer, 34);
+                       int daylight_hour = BitConverter.ToInt16 (buffer, 36);
+                       int daylight_minute = BitConverter.ToInt16 (buffer, 38);
+                       int daylight_second = BitConverter.ToInt16 (buffer, 40);
+                       int daylight_millisecond = BitConverter.ToInt16 (buffer, 42);
+
+                       if (standard_month == 0 || daylight_month == 0)
+                               return;
+
+                       DateTime start_date;
+                       DateTime start_timeofday = new DateTime (1, 1, 1, daylight_hour, daylight_minute, daylight_second, daylight_millisecond);
+                       TransitionTime start_transition_time;
+
+                       if (daylight_year == 0) {
+                               start_date = new DateTime (start_year, 1, 1);
+                               start_transition_time = TransitionTime.CreateFloatingDateRule (
+                                       start_timeofday, daylight_month, daylight_day,
+                                       (DayOfWeek) daylight_dayofweek);
+                       }
+                       else {
+                               start_date = new DateTime (daylight_year, daylight_month, daylight_day,
+                                       daylight_hour, daylight_minute, daylight_second, daylight_millisecond);
+                               start_transition_time = TransitionTime.CreateFixedDateRule (
+                                       start_timeofday, daylight_month, daylight_day);
+                       }
+
+                       DateTime end_date;
+                       DateTime end_timeofday = new DateTime (1, 1, 1, standard_hour, standard_minute, standard_second, standard_millisecond);
+                       TransitionTime end_transition_time;
+
+                       if (standard_year == 0) {
+                               end_date = new DateTime (end_year, 12, 31);
+                               end_transition_time = TransitionTime.CreateFloatingDateRule (
+                                       end_timeofday, standard_month, standard_day,
+                                       (DayOfWeek) standard_dayofweek);
+                       }
+                       else {
+                               end_date = new DateTime (standard_year, standard_month, standard_day,
+                                       standard_hour, standard_minute, standard_second, standard_millisecond);
+                               end_transition_time = TransitionTime.CreateFixedDateRule (
+                                       end_timeofday, standard_month, standard_day);
+                       }
+
+                       TimeSpan daylight_delta = new TimeSpan(0, -daylight_bias, 0);
+
+                       adjustmentRules.Add (AdjustmentRule.CreateAdjustmentRule (
+                               start_date, end_date, daylight_delta,
+                               start_transition_time, end_transition_time));
+               }
+#endif
+
                public static TimeZoneInfo FromSerializedString (string source)
                {
                        throw new NotImplementedException ();
@@ -316,7 +558,7 @@ namespace System
 
                public AdjustmentRule [] GetAdjustmentRules ()
                {
-                       if (disableDaylightSavingTime)
+                       if (!supportsDaylightSavingTime)
                                return new AdjustmentRule [0];
                        else
                                return (AdjustmentRule []) adjustmentRules.Clone ();
@@ -328,7 +570,10 @@ namespace System
                                throw new ArgumentException ("dateTime is not an ambiguous time");
 
                        AdjustmentRule rule = GetApplicableRule (dateTime);
-                       return new TimeSpan[] {baseUtcOffset, baseUtcOffset + rule.DaylightDelta};
+                       if (rule != null)
+                               return new TimeSpan[] {baseUtcOffset, baseUtcOffset + rule.DaylightDelta};
+                       else
+                               return new TimeSpan[] {baseUtcOffset, baseUtcOffset};
                }
 
                public TimeSpan [] GetAmbiguousTimeOffsets (DateTimeOffset dateTimeOffset)
@@ -347,18 +592,47 @@ namespace System
                        return hash_code;
                }
 
+#if NET_4_0
+               void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
+#else
                public void GetObjectData (SerializationInfo info, StreamingContext context)
+#endif
                {
                        throw new NotImplementedException ();
                }
 
                //FIXME: change this to a generic Dictionary and allow caching for FindSystemTimeZoneById
-               private static List<TimeZoneInfo> systemTimeZones = null;
+               private static List<TimeZoneInfo> systemTimeZones;
                public static ReadOnlyCollection<TimeZoneInfo> GetSystemTimeZones ()
                {
                        if (systemTimeZones == null) {
                                systemTimeZones = new List<TimeZoneInfo> ();
-#if LIBC
+#if !NET_2_1
+                               if (TimeZoneKey != null) {
+                                       foreach (string id in TimeZoneKey.GetSubKeyNames ()) {
+                                               try {
+                                                       systemTimeZones.Add (FindSystemTimeZoneById (id));
+                                               } catch {}
+                                       }
+
+                                       return new ReadOnlyCollection<TimeZoneInfo> (systemTimeZones);
+                               }
+#endif
+#if MONODROID
+                       foreach (string id in ZoneInfoDB.GetAvailableIds ()) {
+                               var tz = ZoneInfoDB.GetTimeZone (id);
+                               if (tz != null)
+                                       systemTimeZones.Add (tz);
+                       }
+#elif MONOTOUCH
+                               if (systemTimeZones.Count == 0) {
+                                       foreach (string name in GetMonoTouchNames ()) {
+                                               using (Stream stream = GetMonoTouchData (name)) {
+                                                       systemTimeZones.Add (BuildFromStream (name, stream));
+                                               }
+                                       }
+                               }
+#elif LIBC
                                string[] continents = new string [] {"Africa", "America", "Antarctica", "Arctic", "Asia", "Atlantic", "Brazil", "Canada", "Chile", "Europe", "Indian", "Mexico", "Mideast", "Pacific", "US"};
                                foreach (string continent in continents) {
                                        try {
@@ -386,7 +660,8 @@ namespace System
                {
                        if (IsDaylightSavingTime (dateTime)) {
                                AdjustmentRule rule = GetApplicableRule (dateTime);
-                               return BaseUtcOffset + rule.DaylightDelta;
+                               if (rule != null)
+                                       return BaseUtcOffset + rule.DaylightDelta;
                        }
                        
                        return BaseUtcOffset;
@@ -437,9 +712,11 @@ namespace System
                                dateTime = ConvertTime (dateTime, TimeZoneInfo.Local, this);
 
                        AdjustmentRule rule = GetApplicableRule (dateTime);
-                       DateTime tpoint = TransitionPoint (rule.DaylightTransitionEnd, dateTime.Year);
-                       if (dateTime > tpoint - rule.DaylightDelta  && dateTime <= tpoint)
-                               return true;
+                       if (rule != null) {
+                               DateTime tpoint = TransitionPoint (rule.DaylightTransitionEnd, dateTime.Year);
+                               if (dateTime > tpoint - rule.DaylightDelta  && dateTime <= tpoint)
+                                       return true;
+                       }
                                
                        return false;
                }
@@ -494,14 +771,20 @@ namespace System
                                return false;
 
                        AdjustmentRule rule = GetApplicableRule (dateTime);
-                       DateTime tpoint = TransitionPoint (rule.DaylightTransitionStart, dateTime.Year);
-                       if (dateTime >= tpoint && dateTime < tpoint + rule.DaylightDelta)
-                               return true;
+                       if (rule != null) {
+                               DateTime tpoint = TransitionPoint (rule.DaylightTransitionStart, dateTime.Year);
+                               if (dateTime >= tpoint && dateTime < tpoint + rule.DaylightDelta)
+                                       return true;
+                       }
                                
                        return false;
                }
 
+#if NET_4_0
+               void IDeserializationCallback.OnDeserialization (object sender)
+#else
                public void OnDeserialization (object sender)
+#endif
                {
                        throw new NotImplementedException ();
                }
@@ -535,6 +818,8 @@ namespace System
                                throw new ArgumentException ("id parameter shouldn't be longer than 32 characters");
 #endif
 
+                       bool supportsDaylightSavingTime = !disableDaylightSavingTime;
+
                        if (adjustmentRules != null && adjustmentRules.Length != 0) {
                                AdjustmentRule prev = null;
                                foreach (AdjustmentRule current in adjustmentRules) {
@@ -556,6 +841,8 @@ namespace System
 
                                        prev = current;
                                }
+                       } else {
+                               supportsDaylightSavingTime = false;
                        }
                        
                        this.id = id;
@@ -563,7 +850,7 @@ namespace System
                        this.displayName = displayName ?? id;
                        this.standardDisplayName = standardDisplayName ?? id;
                        this.daylightDisplayName = daylightDisplayName;
-                       this.disableDaylightSavingTime = disableDaylightSavingTime;
+                       this.supportsDaylightSavingTime = supportsDaylightSavingTime;
                        this.adjustmentRules = adjustmentRules;
                }
 
@@ -578,12 +865,14 @@ namespace System
                        if (dateTime.Kind == DateTimeKind.Utc && this != TimeZoneInfo.Utc)
                                date = date + BaseUtcOffset;
 
-                       foreach (AdjustmentRule rule in adjustmentRules) {
-                               if (rule.DateStart > date.Date)
-                                       return null;
-                               if (rule.DateEnd < date.Date)
-                                       continue;
-                               return rule;
+                       if (adjustmentRules != null) {
+                               foreach (AdjustmentRule rule in adjustmentRules) {
+                                       if (rule.DateStart > date.Date)
+                                               return null;
+                                       if (rule.DateEnd < date.Date)
+                                               continue;
+                                       return rule;
+                               }
                        }
                        return null;
                }
@@ -600,7 +889,19 @@ namespace System
                        return new DateTime (year, transition.Month, day) + transition.TimeOfDay.TimeOfDay;
                }
 
-#if LIBC
+               static List<AdjustmentRule> ValidateRules (List<AdjustmentRule> adjustmentRules)
+               {
+                       AdjustmentRule prev = null;
+                       foreach (AdjustmentRule current in adjustmentRules.ToArray ()) {
+                               if (prev != null && prev.DateEnd > current.DateStart) {
+                                       adjustmentRules.Remove (current);
+                               }
+                               prev = current;
+                       }
+                       return adjustmentRules;
+               }
+
+#if LIBC || MONODROID
                private static bool ValidTZFile (byte [] buffer, int length)
                {
                        StringBuilder magic = new StringBuilder ();
@@ -617,25 +918,6 @@ namespace System
                        return true;
                }
 
-               struct TimeType 
-               {
-                       public readonly int Offset;
-                       public readonly bool IsDst;
-                       public string Name;
-
-                       public TimeType (int offset, bool is_dst, string abbrev)
-                       {
-                               this.Offset = offset;
-                               this.IsDst = is_dst;
-                               this.Name = abbrev;
-                       }
-
-                       public override string ToString ()
-                       {
-                               return "offset: " + Offset + "s, is_dst: " + IsDst + ", zone name: " + Name;
-                       }
-               }
-
                static int SwapInt32 (int i)
                {
                        return (((i >> 24) & 0xff)
@@ -746,18 +1028,6 @@ namespace System
                        }
                }
 
-               static List<AdjustmentRule> ValidateRules (List<AdjustmentRule> adjustmentRules)
-               {
-                       AdjustmentRule prev = null;
-                       foreach (AdjustmentRule current in adjustmentRules.ToArray ()) {
-                               if (prev != null && prev.DateEnd > current.DateStart) {
-                                       adjustmentRules.Remove (current);
-                               }
-                               prev = current;
-                       }
-                       return adjustmentRules;
-               }
-
                static Dictionary<int, string> ParseAbbreviations (byte [] buffer, int index, int count)
                {
                        var abbrevs = new Dictionary<int, string> ();
@@ -808,6 +1078,28 @@ namespace System
                        DateTime date_time = new DateTime (1970, 1, 1);
                        return date_time.AddSeconds (unix_time);
                }
+       }
+
+       struct TimeType {
+               public readonly int Offset;
+               public readonly bool IsDst;
+               public string Name;
+
+               public TimeType (int offset, bool is_dst, string abbrev)
+               {
+                       this.Offset = offset;
+                       this.IsDst = is_dst;
+                       this.Name = abbrev;
+               }
+
+               public override string ToString ()
+               {
+                       return "offset: " + Offset + "s, is_dst: " + IsDst + ", zone name: " + Name;
+               }
+#else
+       }
 #endif
        }
 }
+
+#endif