[monodroid] Add support for the Android TimeZone file format.
[mono.git] / mcs / class / System.Core / System / TimeZoneInfo.cs
index 6b49ddb760a13d1e76defd149c3d2b54faada535..cb464b54ad9cf17060cb97c7c1978c54a4b4bab6 100644 (file)
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-using System.Runtime.Serialization;
+using System;
+using System.Runtime.CompilerServices;
+
+#if !INSIDE_CORLIB && (NET_4_0 || BOOTSTRAP_NET_4_0 || MOONLIGHT)
+
+[assembly:TypeForwardedTo (typeof(TimeZoneInfo))]
+
+#elif NET_3_5 || (MOBILE && !INSIDE_CORLIB) || (MOONLIGHT && INSIDE_CORLIB)
+
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
-#if LIBC
+using System.Linq;
+using System.Runtime.Serialization;
+using System.Text;
+
+#if LIBC || MONODROID
 using System.IO;
-using System.Collections;
 using Mono;
 #endif
 
+using Microsoft.Win32;
+
 namespace System
 {
+#if NET_4_0 || BOOTSTRAP_NET_4_0
+       [TypeForwardedFrom (Consts.AssemblySystemCore_3_5)]
+#elif MOONLIGHT
+       [TypeForwardedFrom (Consts.AssemblySystem_Core)]
+#endif
        [SerializableAttribute]
        public sealed partial class TimeZoneInfo : IEquatable<TimeZoneInfo>, ISerializable, IDeserializationCallback
        {
@@ -66,7 +84,9 @@ namespace System
                public static TimeZoneInfo Local {
                        get { 
                                if (local == null) {
-#if LIBC
+#if MONODROID
+                                       local = ZoneInfoDB.Default;
+#elif LIBC
                                        try {
                                                local = FindSystemTimeZoneByFileName ("Local", "/etc/localtime");       
                                        } catch {
@@ -104,7 +124,7 @@ namespace System
                }
 #if LIBC
                static string timeZoneDirectory = null;
-               public static string TimeZoneDirectory {
+               static string TimeZoneDirectory {
                        get {
                                if (timeZoneDirectory == null)
                                        timeZoneDirectory = "/usr/share/zoneinfo";
@@ -118,6 +138,25 @@ namespace System
 #endif
                private AdjustmentRule [] adjustmentRules;
 
+#if !NET_2_1
+               static RegistryKey timeZoneKey = null;
+               static bool timeZoneKeySet = false;
+               static RegistryKey TimeZoneKey {
+                       get {
+                               if (!timeZoneKeySet) {
+                                       int p = (int) Environment.OSVersion.Platform;
+                                       /* Only use the registry on non-Unix platforms. */
+                                       if ((p != 4) && (p != 6) && (p != 128))
+                                               timeZoneKey = Registry.LocalMachine.OpenSubKey (
+                                                       "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
+                                                       false);
+                                       timeZoneKeySet = true;
+                               }
+                               return timeZoneKey;
+                       }
+               }
+#endif
+
                public static void ClearCachedData ()
                {
                        local = null;
@@ -275,7 +314,18 @@ 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
+                       return ZoneInfoDB.GetTimeZone (id);
+#elif LIBC
                        string filepath = Path.Combine (TimeZoneDirectory, id);
                        return FindSystemTimeZoneByFileName (id, filepath);
 #else
@@ -284,7 +334,7 @@ namespace System
                }
 
 #if LIBC
-               const int BUFFER_SIZE = 8192; //Big enough for any tz file
+               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))
@@ -297,7 +347,7 @@ namespace System
                        }
 
                        if (!ValidTZFile (buffer, length))
-                               throw new InvalidTimeZoneException ();
+                               throw new InvalidTimeZoneException ("TZ file too big for the buffer");
 
                        try {
                                return ParseTZBuffer (id, buffer, length);
@@ -307,6 +357,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 ();
@@ -345,7 +501,11 @@ 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 ();
                }
@@ -356,7 +516,21 @@ namespace System
                {
                        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
+                       systemTimeZones.AddRange (ZoneInfoDB.GetAvailableIds ()
+                                       .Select (id => ZoneInfoDB.GetTimeZone (id)));
+#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 {
@@ -367,13 +541,8 @@ namespace System
                                                        } catch (ArgumentNullException) {
                                                        } catch (TimeZoneNotFoundException) {
                                                        } catch (InvalidTimeZoneException) {
-                                                       } catch (Exception e) {
-                                                               if (e is OutOfMemoryException || e is System.Security.SecurityException)
-                                                                       throw;
-                                                               else {
-                                                                       Console.WriteLine ("Unexpected Exception");
-                                                                       throw;
-                                                               }
+                                                       } catch (Exception) {
+                                                               throw;
                                                        }
                                                }
                                        } catch {}
@@ -405,6 +574,12 @@ namespace System
                        if (other == null)
                                throw new ArgumentNullException ("other");
 
+                       if ((this.adjustmentRules == null) != (other.adjustmentRules == null))
+                               return false;
+
+                       if (this.adjustmentRules == null)
+                               return true;
+
                        if (this.BaseUtcOffset != other.BaseUtcOffset)
                                return false;
 
@@ -475,7 +650,7 @@ namespace System
                                DST_end -= (BaseUtcOffset + rule.DaylightDelta);
                        }
 
-                       return (dateTime >= DST_start && dateTime < DST_end)
+                       return (dateTime >= DST_start && dateTime < DST_end);
                }
 
                public bool IsDaylightSavingTime (DateTimeOffset dateTimeOffset)
@@ -498,7 +673,11 @@ namespace System
                        return false;
                }
 
+#if NET_4_0
+               void IDeserializationCallback.OnDeserialization (object sender)
+#else
                public void OnDeserialization (object sender)
+#endif
                {
                        throw new NotImplementedException ();
                }
@@ -575,12 +754,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;
                }
@@ -597,10 +778,22 @@ 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)
                {
-                       System.Text.StringBuilder magic = new System.Text.StringBuilder ();
+                       StringBuilder magic = new StringBuilder ();
 
                        for (int i = 0; i < 4; i++)
                                magic.Append ((char)buffer [i]);
@@ -614,55 +807,58 @@ namespace System
                        return true;
                }
 
-               private struct TimeType 
+               struct TimeType 
                {
-                       int offset;
-                       bool is_dst;
-                       string abbrev;
-                       
+                       public readonly int Offset;
+                       public readonly bool IsDst;
+                       public string Name;
+
                        public TimeType (int offset, bool is_dst, string abbrev)
                        {
-                               this.offset = offset;
-                               this.is_dst = is_dst;
-                               this.abbrev = abbrev;
+                               this.Offset = offset;
+                               this.IsDst = is_dst;
+                               this.Name = abbrev;
                        }
 
-                       public int Offset {
-                               get { return offset; }
+                       public override string ToString ()
+                       {
+                               return "offset: " + Offset + "s, is_dst: " + IsDst + ", zone name: " + Name;
                        }
+               }
 
-                       public bool IsDst {
-                               get { return is_dst; }
-                       }
+               static int SwapInt32 (int i)
+               {
+                       return (((i >> 24) & 0xff)
+                               | ((i >> 8) & 0xff00)
+                               | ((i << 8) & 0xff0000)
+                               | ((i << 24)));
+               }
 
-                       public string Name {
-                               get { return abbrev; }
-                       }
+               static int ReadBigEndianInt32 (byte [] buffer, int start)
+               {
+                       int i = BitConverter.ToInt32 (buffer, start);
+                       if (!BitConverter.IsLittleEndian)
+                               return i;
 
-                       public override string ToString ()
-                       {
-                               return "offset: " + offset + "s, is_dst: " + is_dst + ", zone name: " + abbrev;
-                       }
+                       return SwapInt32 (i);
                }
 
                private static TimeZoneInfo ParseTZBuffer (string id, byte [] buffer, int length)
                {
-                       DataConverter enc = DataConverter.BigEndian;
-
                        //Reading the header. 4 bytes for magic, 16 are reserved
-                       int ttisgmtcnt = enc.GetInt32 (buffer, 20);
-                       int ttisstdcnt = enc.GetInt32 (buffer, 24);
-                       int leapcnt = enc.GetInt32 (buffer, 28);
-                       int timecnt = enc.GetInt32 (buffer, 32);
-                       int typecnt = enc.GetInt32 (buffer, 36);
-                       int charcnt = enc.GetInt32 (buffer, 40);
-
-                       if (length != 44 + timecnt * 5 + typecnt * 6 + charcnt + leapcnt * 8 + ttisstdcnt + ttisgmtcnt)
+                       int ttisgmtcnt = ReadBigEndianInt32 (buffer, 20);
+                       int ttisstdcnt = ReadBigEndianInt32 (buffer, 24);
+                       int leapcnt = ReadBigEndianInt32 (buffer, 28);
+                       int timecnt = ReadBigEndianInt32 (buffer, 32);
+                       int typecnt = ReadBigEndianInt32 (buffer, 36);
+                       int charcnt = ReadBigEndianInt32 (buffer, 40);
+
+                       if (length < 44 + timecnt * 5 + typecnt * 6 + charcnt + leapcnt * 8 + ttisstdcnt + ttisgmtcnt)
                                throw new InvalidTimeZoneException ();
 
-                       Hashtable abbreviations = ParseAbbreviations (buffer, 44 + 4 * timecnt + timecnt + 6 * typecnt, charcnt);
-                       Hashtable time_types = ParseTimesTypes (buffer, 44 + 4 * timecnt + timecnt, typecnt, abbreviations);
-                       SortedList transitions = ParseTransitions (buffer, 44, timecnt, time_types);
+                       Dictionary<int, string> abbreviations = ParseAbbreviations (buffer, 44 + 4 * timecnt + timecnt + 6 * typecnt, charcnt);
+                       Dictionary<int, TimeType> time_types = ParseTimesTypes (buffer, 44 + 4 * timecnt + timecnt, typecnt, abbreviations);
+                       List<KeyValuePair<DateTime, TimeType>> transitions = ParseTransitions (buffer, 44, timecnt, time_types);
 
                        if (time_types.Count == 0)
                                throw new InvalidTimeZoneException ();
@@ -679,8 +875,9 @@ namespace System
                        List<AdjustmentRule> adjustmentRules = new List<AdjustmentRule> ();
 
                        for (int i = 0; i < transitions.Count; i++) {
-                               DateTime ttime = (DateTime) transitions.GetKey (i);
-                               TimeType ttype = (TimeType) transitions [ttime];
+                               var pair = transitions [i];
+                               DateTime ttime = pair.Key;
+                               TimeType ttype = pair.Value;
                                if (!ttype.IsDst) {
                                        if (standardDisplayName != ttype.Name || baseUtcOffset.TotalSeconds != ttype.Offset) {
                                                standardDisplayName = ttype.Name;
@@ -695,6 +892,10 @@ namespace System
                                                dst_start += baseUtcOffset;
                                                DateTime dst_end = ttime + baseUtcOffset + dstDelta;
 
+                                               //some weird timezone (America/Phoenix) have end dates on Jan 1st
+                                               if (dst_end.Date == new DateTime (dst_end.Year, 1, 1) && dst_end.Year > dst_start.Year)
+                                                       dst_end -= new TimeSpan (24, 0, 0);
+
                                                DateTime dateStart, dateEnd;
                                                if (dst_start.Month < 7)
                                                        dateStart = new DateTime (dst_start.Year, 1, 1);
@@ -702,13 +903,15 @@ namespace System
                                                        dateStart = new DateTime (dst_start.Year, 7, 1);
 
                                                if (dst_end.Month >= 7)
-                                                       dateEnd = new DateTime (dst_start.Year, 12, 31);
+                                                       dateEnd = new DateTime (dst_end.Year, 12, 31);
                                                else
                                                        dateEnd = new DateTime (dst_end.Year, 6, 30);
 
+                                               
                                                TransitionTime transition_start = TransitionTime.CreateFixedDateRule (new DateTime (1, 1, 1) + dst_start.TimeOfDay, dst_start.Month, dst_start.Day);
                                                TransitionTime transition_end = TransitionTime.CreateFixedDateRule (new DateTime (1, 1, 1) + dst_end.TimeOfDay, dst_end.Month, dst_end.Day);
-                                               adjustmentRules.Add (AdjustmentRule.CreateAdjustmentRule (dateStart, dateEnd, dstDelta, transition_start, transition_end));
+                                               if  (transition_start != transition_end) //y, that happened in Argentina in 1943-1946
+                                                       adjustmentRules.Add (AdjustmentRule.CreateAdjustmentRule (dateStart, dateEnd, dstDelta, transition_start, transition_end));
                                        }
                                        dst_observed = false;
                                } else {
@@ -729,55 +932,56 @@ namespace System
                                }
                                return CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName);
                        } else {
-                               return CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName, daylightDisplayName, adjustmentRules.ToArray ());
+                               return CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName, daylightDisplayName, ValidateRules (adjustmentRules).ToArray ());
                        }
                }
 
-               private static Hashtable ParseAbbreviations (byte [] buffer, int index, int count)
+               static Dictionary<int, string> ParseAbbreviations (byte [] buffer, int index, int count)
                {
-                       Hashtable abbrevs = new Hashtable ();
+                       var abbrevs = new Dictionary<int, string> ();
                        int abbrev_index = 0;
-                       System.Text.StringBuilder sb = new System.Text.StringBuilder ();
+                       var sb = new StringBuilder ();
                        for (int i = 0; i < count; i++) {
                                char c = (char) buffer [index + i];
                                if (c != '\0')
                                        sb.Append (c);
                                else {
                                        abbrevs.Add (abbrev_index, sb.ToString ());
+                                       //Adding all the substrings too, as it seems to be used, at least for Africa/Windhoek
+                                       for (int j = 1; j < sb.Length; j++)
+                                               abbrevs.Add (abbrev_index + j, sb.ToString (j, sb.Length - j));
                                        abbrev_index = i + 1;
-                                       sb = new System.Text.StringBuilder ();
+                                       sb = new StringBuilder ();
                                }
                        }
                        return abbrevs;
                }
 
-               private static Hashtable ParseTimesTypes (byte [] buffer, int index, int count, Hashtable abbreviations)
+               static Dictionary<int, TimeType> ParseTimesTypes (byte [] buffer, int index, int count, Dictionary<int, string> abbreviations)
                {
-                       DataConverter enc = DataConverter.BigEndian;
-                       Hashtable types = new Hashtable (count);
+                       var types = new Dictionary<int, TimeType> (count);
                        for (int i = 0; i < count; i++) {
-                               int offset = enc.GetInt32 (buffer, index + 6 * i);
+                               int offset = ReadBigEndianInt32 (buffer, index + 6 * i);
                                byte is_dst = buffer [index + 6 * i + 4];
                                byte abbrev = buffer [index + 6 * i + 5];
-                               types.Add (i, new TimeType (offset, (is_dst != 0), abbreviations [(int)abbrev] as string));
+                               types.Add (i, new TimeType (offset, (is_dst != 0), abbreviations [(int)abbrev]));
                        }
                        return types;
                }
 
-               private static SortedList ParseTransitions (byte [] buffer, int index, int count, Hashtable time_types)
+               static List<KeyValuePair<DateTime, TimeType>> ParseTransitions (byte [] buffer, int index, int count, Dictionary<int, TimeType> time_types)
                {
-                       DataConverter enc = DataConverter.BigEndian;
-                       SortedList trans = new SortedList (count);
+                       var list = new List<KeyValuePair<DateTime, TimeType>> (count);
                        for (int i = 0; i < count; i++) {
-                               int unixtime = enc.GetInt32 (buffer, index + 4 * i);
+                               int unixtime = ReadBigEndianInt32 (buffer, index + 4 * i);
                                DateTime ttime = DateTimeFromUnixTime (unixtime);
                                byte ttype = buffer [index + 4 * count + i];
-                               trans.Add (ttime, time_types [(int)ttype]);
+                               list.Add (new KeyValuePair<DateTime, TimeType> (ttime, time_types [(int)ttype]));
                        }
-                       return trans;
+                       return list;
                }
 
-               private static DateTime DateTimeFromUnixTime (long unix_time)
+               static DateTime DateTimeFromUnixTime (long unix_time)
                {
                        DateTime date_time = new DateTime (1970, 1, 1);
                        return date_time.AddSeconds (unix_time);
@@ -785,3 +989,5 @@ namespace System
 #endif
        }
 }
+
+#endif