diff options
author | Miguel de Icaza <miguel@gnome.org> | 2010-06-19 03:38:07 +0400 |
---|---|---|
committer | Miguel de Icaza <miguel@gnome.org> | 2010-06-19 03:38:07 +0400 |
commit | b433a909ab4658cd1c0f5cea95f89094ae26c696 (patch) | |
tree | 83faccc0237e4877952a4180359e3548e3949799 /mcs/class | |
parent | 5e585590bbf5d7c05497b948556becf277719d21 (diff) |
Backport
svn path=/branches/mono-2-6/mcs/; revision=159164
Diffstat (limited to 'mcs/class')
-rw-r--r-- | mcs/class/System.Core/System/TimeZoneInfo.cs | 170 |
1 files changed, 155 insertions, 15 deletions
diff --git a/mcs/class/System.Core/System/TimeZoneInfo.cs b/mcs/class/System.Core/System/TimeZoneInfo.cs index d5e77e89709..0f5889ed958 100644 --- a/mcs/class/System.Core/System/TimeZoneInfo.cs +++ b/mcs/class/System.Core/System/TimeZoneInfo.cs @@ -43,6 +43,8 @@ using System.IO; using Mono; #endif +using Microsoft.Win32; + namespace System { #if NET_4_0 || BOOTSRAP_NET_4_0 @@ -131,6 +133,23 @@ namespace System #endif private AdjustmentRule [] adjustmentRules; + 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; + } + } + public static void ClearCachedData () { local = null; @@ -288,6 +307,13 @@ namespace System //FIXME: this method should check for cached values in systemTimeZones if (id == null) throw new ArgumentNullException ("id"); + if (TimeZoneKey != null) + { + RegistryKey key = TimeZoneKey.OpenSubKey (id, false); + if (key == null) + throw new TimeZoneNotFoundException (); + return FromRegistryKey(id, key); + } #if LIBC string filepath = Path.Combine (TimeZoneDirectory, id); return FindSystemTimeZoneByFileName (id, filepath); @@ -320,6 +346,110 @@ namespace System } #endif + 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)); + } + public static TimeZoneInfo FromSerializedString (string source) { throw new NotImplementedException (); @@ -369,25 +499,35 @@ namespace System { if (systemTimeZones == null) { systemTimeZones = new List<TimeZoneInfo> (); + if (TimeZoneKey != null) { + foreach (string id in TimeZoneKey.GetSubKeyNames ()) { + try { + systemTimeZones.Add (FindSystemTimeZoneById (id)); + } catch {} + } + } #if 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 { - foreach (string zonepath in Directory.GetFiles (Path.Combine (TimeZoneDirectory, continent))) { - try { - string id = String.Format ("{0}/{1}", continent, Path.GetFileName (zonepath)); - systemTimeZones.Add (FindSystemTimeZoneById (id)); - } catch (ArgumentNullException) { - } catch (TimeZoneNotFoundException) { - } catch (InvalidTimeZoneException) { - } catch (Exception) { - throw; + else { + 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 { + foreach (string zonepath in Directory.GetFiles (Path.Combine (TimeZoneDirectory, continent))) { + try { + string id = String.Format ("{0}/{1}", continent, Path.GetFileName (zonepath)); + systemTimeZones.Add (FindSystemTimeZoneById (id)); + } catch (ArgumentNullException) { + } catch (TimeZoneNotFoundException) { + } catch (InvalidTimeZoneException) { + } catch (Exception) { + throw; + } } - } - } catch {} + } catch {} + } } #else - throw new NotImplementedException ("This method is not implemented for this platform"); + else + throw new NotImplementedException ("This method is not implemented for this platform"); #endif } return new ReadOnlyCollection<TimeZoneInfo> (systemTimeZones); |