Merge pull request #1696 from esdrubal/tzrefactor
authorMarcos Henrich <marcoshenrich@gmail.com>
Tue, 28 Apr 2015 15:36:08 +0000 (16:36 +0100)
committerMarcos Henrich <marcoshenrich@gmail.com>
Tue, 28 Apr 2015 15:36:08 +0000 (16:36 +0100)
TimeZone Refactoring.

mcs/class/corlib/System/AndroidPlatform.cs
mcs/class/corlib/System/TimeZone.cs
mcs/class/corlib/System/TimeZoneInfo.cs
mcs/class/corlib/Test/System/TimeZoneTest.cs
mono/metadata/icall-def.h
mono/metadata/icall.c

index 75e3d6a855fb792cbb38121ea95bec8dec8deba9..ae59c7c9c5a2461bc442b66fc36115adf2c3314d 100644 (file)
@@ -36,7 +36,6 @@ namespace System {
 
                static readonly Func<SynchronizationContext> getDefaultSyncContext;
                static readonly Func<string> getDefaultTimeZone;
-               static readonly Func<TimeZone> getCurrentSystemTimeZone;
 
                static AndroidPlatform ()
                {
@@ -51,11 +50,6 @@ namespace System {
                                Delegate.CreateDelegate (typeof(Func<string>), 
                                                androidRuntime.GetMethod ("GetDefaultTimeZone",
                                                        System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic));
-
-                       MethodInfo mi = androidRuntime.GetMethod ("GetCurrentSystemTimeZone",
-                                       System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
-                       if (mi != null)
-                               getCurrentSystemTimeZone = (Func<TimeZone>) Delegate.CreateDelegate (typeof(Func<TimeZone>), mi);
                }
 
                internal static SynchronizationContext GetDefaultSyncContext ()
@@ -67,13 +61,6 @@ namespace System {
                {
                        return getDefaultTimeZone ();
                }
-
-               internal static TimeZone GetCurrentSystemTimeZone ()
-               {
-                       if (getCurrentSystemTimeZone == null)
-                               return null;
-                       return getCurrentSystemTimeZone ();
-               }
        }
 }
 #endif
index 61d088a6593af1fcf408f27cc668e0cbfa384bd3..1cfa2ee9bcc3ecc73cacc8acac49ad997e890cde 100644 (file)
@@ -73,11 +73,7 @@ namespace System
                                
                                lock (tz_lock) {
                                        if (tz == null || Math.Abs (now - timezone_check) > TimeSpan.TicksPerMinute) {
-#if MONODROID
-                                               tz = AndroidPlatform.GetCurrentSystemTimeZone ();
-                                               if (tz == null)
-#endif
-                                                       tz = new CurrentSystemTimeZone (now);
+                                               tz = new CurrentSystemTimeZone ();
                                                timezone_check = now;
 
                                                currentTimeZone = tz;
@@ -169,205 +165,50 @@ namespace System
                {
                        currentTimeZone = null;
                }
-
-               //
-               // This routine returns the TimeDiff that would have to be
-               // added to "time" to turn it into a local time.   This would
-               // be equivalent to call ToLocalTime.
-               //
-               // There is one important consideration:
-               //
-               //    This information is only valid during the minute it
-               //    was called.
-               //
-               //    This only works with a real time, not one of the boundary
-               //    cases like DateTime.MaxValue, so validation must be done
-               //    before.
-               // 
-               //    This is intended to be used by DateTime.Now
-               //
-               // We use a minute, just to be conservative and cope with
-               // any potential time zones that might be defined in the future
-               // that might not nicely fit in hour or half-hour steps. 
-               //    
-               internal TimeSpan GetLocalTimeDiff (DateTime time)
-               {
-                       return GetLocalTimeDiff (time, GetUtcOffset (time));
-               }
-
-               //
-               // This routine is intended to be called by GetLocalTimeDiff(DatetTime)
-               // or by ToLocalTime after validation has been performed
-               //
-               // time is the time to map, utc_offset is the utc_offset that
-               // has been computed for calling GetUtcOffset on time.
-               //
-               // When called by GetLocalTime, utc_offset is assumed to come
-               // from a time constructed by new DateTime (DateTime.GetNow ()), that
-               // is a valid time.
-               //
-               // When called by ToLocalTime ranges are checked before this is
-               // called.
-               //
-               internal TimeSpan GetLocalTimeDiff (DateTime time, TimeSpan utc_offset)
-               {
-                       DaylightTime dlt = GetDaylightChanges (time.Year);
-
-                       if (dlt.Delta.Ticks == 0)
-                               return utc_offset;
-
-                       DateTime local = time.Add (utc_offset);
-                       if (local < dlt.End && dlt.End.Subtract (dlt.Delta) <= local)
-                               return utc_offset;
-
-                       if (local >= dlt.Start && dlt.Start.Add (dlt.Delta) > local)
-                               return utc_offset - dlt.Delta;
-
-                       return GetUtcOffset (local);
-               }
        }
 
        [Serializable]
-       internal class CurrentSystemTimeZone : TimeZone, IDeserializationCallback {
+       internal class CurrentSystemTimeZone : TimeZone {
 
-               // Fields
-               private string m_standardName;
-               private string m_daylightName;
-
-               // A yearwise cache of DaylightTime.
-               private Dictionary<int, DaylightTime> m_CachedDaylightChanges = new Dictionary<int, DaylightTime> (1);
-
-               internal enum TimeZoneData
-               {
-                       DaylightSavingStartIdx,
-                       DaylightSavingEndIdx,
-                       UtcOffsetIdx,
-                       AdditionalDaylightOffsetIdx
-               };
-
-               internal enum TimeZoneNames
-               {
-                       StandardNameIdx,
-                       DaylightNameIdx
-               };
-
-               // Internal method to get timezone data.
-               //    data[0]:  start of daylight saving time (in DateTime ticks).
-               //    data[1]:  end of daylight saving time (in DateTime ticks).
-               //    data[2]:  utcoffset (in TimeSpan ticks).
-               //    data[3]:  additional offset when daylight saving (in TimeSpan ticks).
-               //    name[0]:  name of this timezone when not daylight saving.
-               //    name[1]:  name of this timezone when daylight saving.
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private static extern bool GetTimeZoneData (int year, out Int64[] data, out string[] names);
+               readonly  TimeZoneInfo  LocalTimeZone;
 
                // Constructor
                internal CurrentSystemTimeZone ()
                {
+                       LocalTimeZone = TimeZoneInfo.Local;
                }
 
-               //
-               // Initialized by the constructor
-               //
-               static int this_year;
-               static DaylightTime this_year_dlt;
-               
-               //
-               // The "lnow" parameter must be the current time, I could have moved
-               // the code here, but I do not want to interfere with serialization
-               // which is why I kept the other constructor around
-               //
-               internal CurrentSystemTimeZone (long lnow)
-               {
-                       Int64[] data;
-                       string[] names;
-
-                       DateTime now = new DateTime (lnow);
-                       if (!GetTimeZoneData (now.Year, out data, out names))
-                               throw new NotSupportedException (Locale.GetText ("Can't get timezone name."));
-
-                       m_standardName = Locale.GetText (names[(int)TimeZoneNames.StandardNameIdx]);
-                       m_daylightName = Locale.GetText (names[(int)TimeZoneNames.DaylightNameIdx]);
-
-                       DaylightTime dlt = GetDaylightTimeFromData (data);
-                       m_CachedDaylightChanges.Add (now.Year, dlt);
-                       OnDeserialization (dlt);
-               }
-
-               // Properties
                public override string DaylightName {
-                       get { return m_daylightName; }
+                       get {
+                               return LocalTimeZone.DaylightName;
+                       }
                }
 
                public override string StandardName {
-                       get { return m_standardName; }
+                       get {
+                               return LocalTimeZone.StandardName;
+                       }
                }
 
-               // Methods
-               public override DaylightTime GetDaylightChanges (int year)
+               public override System.Globalization.DaylightTime GetDaylightChanges (int year)
                {
-                       if (year < 1 || year > 9999)
-                               throw new ArgumentOutOfRangeException ("year", year +
-                                       Locale.GetText (" is not in a range between 1 and 9999."));
-
-                       //
-                       // First we try the case for this year, very common, and is used
-                       // by DateTime.Now (a popular call) indirectly.
-                       //
-                       if (year == this_year)
-                               return this_year_dlt;
-                       
-                       lock (m_CachedDaylightChanges) {
-                               DaylightTime dlt;
-                               if (!m_CachedDaylightChanges.TryGetValue (year, out dlt)) {
-                                       Int64[] data;
-                                       string[] names;
-
-                                       if (!GetTimeZoneData (year, out data, out names))
-                                               throw new ArgumentException (Locale.GetText ("Can't get timezone data for " + year));
-
-                                       dlt = GetDaylightTimeFromData (data);
-                                       m_CachedDaylightChanges.Add (year, dlt);
-                               }
-                               return dlt;
-                       }
+                       return LocalTimeZone.GetDaylightChanges (year);
                }
 
-               public override TimeSpan GetUtcOffset (DateTime time)
+               public override TimeSpan GetUtcOffset (DateTime dateTime)
                {
-                       if (time.Kind == DateTimeKind.Utc)
+                       if (dateTime.Kind == DateTimeKind.Utc)
                                return TimeSpan.Zero;
 
-                       return TimeZoneInfo.Local.GetUtcOffset (time);
-               }
-
-               void IDeserializationCallback.OnDeserialization (object sender)
-               {
-                       OnDeserialization (null);
+                       return LocalTimeZone.GetUtcOffset (dateTime);
                }
 
-               private void OnDeserialization (DaylightTime dlt)
+               public override bool IsDaylightSavingTime (DateTime dateTime)
                {
-                       if (dlt == null) {
-                               Int64[] data;
-                               string[] names;
-
-                               this_year = DateTime.Now.Year;
-                               if (!GetTimeZoneData (this_year, out data, out names))
-                                       throw new ArgumentException (Locale.GetText ("Can't get timezone data for " + this_year));
-                               dlt = GetDaylightTimeFromData (data);
-                       } else
-                               this_year = dlt.Start.Year;
-                       
-                       this_year_dlt = dlt;
-               }
+                       if (dateTime.Kind == DateTimeKind.Utc)
+                               return false;
 
-               private DaylightTime GetDaylightTimeFromData (long[] data)
-               {
-                       return new DaylightTime (new DateTime (data[(int)TimeZoneData.DaylightSavingStartIdx]),
-                               new DateTime (data[(int)TimeZoneData.DaylightSavingEndIdx]),
-                               new TimeSpan (data[(int)TimeZoneData.AdditionalDaylightOffsetIdx]));
+                       return LocalTimeZone.IsDaylightSavingTime (dateTime);
                }
-
        }
 }
index dadd2b7003e8b8b045b054e60d0e345ab4f197ce..0c17412242c835af7107d559a158ce9be1e25444 100644 (file)
@@ -880,6 +880,68 @@ namespace System
                        throw new NotImplementedException ();
                }
 
+               internal DaylightTime GetDaylightChanges (int year)
+               {
+                       DateTime start = DateTime.MinValue, end = DateTime.MinValue;
+                       TimeSpan delta = new TimeSpan ();
+
+                       if (transitions != null) {
+                               end = DateTime.MaxValue;
+                               for (var i =  transitions.Count - 1; i >= 0; i--) {
+                                       var pair = transitions [i];
+                                       DateTime ttime = pair.Key;
+                                       TimeType ttype = pair.Value;
+
+                                       if (ttype.IsDst) {
+                                               // DaylightTime.Delta is relative to the current BaseUtcOffset.
+                                               var d =  new TimeSpan (0, 0, ttype.Offset) - BaseUtcOffset;
+                                               // Handle DST gradients
+                                               if (start != DateTime.MinValue && delta != d)
+                                                       end = start;
+
+                                               start = ttime;
+                                               delta = d;
+
+                                               if (ttime.Year <= year)
+                                                       break;
+                                       } else {
+                                               if (ttime.Year < year)
+                                                       break;
+
+                                               end = ttime;
+                                               start = DateTime.MinValue;
+                                       }
+                               }
+
+                               // DaylightTime.Start is relative to the Standard time.
+                               if (start != DateTime.MinValue)
+                                       start += BaseUtcOffset;
+
+                               // DaylightTime.End is relative to the DST time.
+                               if (end != DateTime.MaxValue)
+                                       end += BaseUtcOffset + delta;
+                       } else {
+                               AdjustmentRule rule = null;
+                               foreach (var r in GetAdjustmentRules ()) {
+                                       if (r.DateEnd.Year < year)
+                                               continue;
+                                       if (r.DateStart.Year > year)
+                                               break;
+                                       rule = r;
+                               }
+                               if (rule != null) {
+                                       start = TransitionPoint (rule.DaylightTransitionStart, year);
+                                       end = TransitionPoint (rule.DaylightTransitionEnd, year);
+                                       delta = rule.DaylightDelta;
+                               }
+                       }
+
+                       if (start == DateTime.MinValue || end == DateTime.MinValue)
+                               return new DaylightTime (new DateTime (), new DateTime (), new TimeSpan ());
+
+                       return new DaylightTime (start, end, delta);
+               }
+
                public bool IsInvalidTime (DateTime dateTime)
                {
                        if (dateTime.Kind == DateTimeKind.Utc)
index 965d2e078e36d3f267b9fcfead09bdca0e99d02b..19e2cb5c49d3fc7bfcf57f254ff011b9159aa9c7 100644 (file)
@@ -27,13 +27,13 @@ public class TimeZoneTest {
                Assert.AreEqual("CEST", t1.DaylightName, "A02");
        
                DaylightTime d1 = t1.GetDaylightChanges (2002);
-               Assert.AreEqual("03/31/2002 02:00:00", d1.Start.ToString ("G"), "A03");
-               Assert.AreEqual("10/27/2002 03:00:00", d1.End.ToString ("G"), "A04");
+               Assert.AreEqual("03/31/2002 02:00:00", d1.Start.ToString ("G", CultureInfo.InvariantCulture), "A03");
+               Assert.AreEqual("10/27/2002 03:00:00", d1.End.ToString ("G", CultureInfo.InvariantCulture), "A04");
                Assert.AreEqual(36000000000L, d1.Delta.Ticks, "A05");
        
                DaylightTime d2 = t1.GetDaylightChanges (1996);
-               Assert.AreEqual("03/31/1996 02:00:00", d2.Start.ToString ("G"), "A06");
-               Assert.AreEqual("10/27/1996 03:00:00", d2.End.ToString ("G"), "A07");
+               Assert.AreEqual("03/31/1996 02:00:00", d2.Start.ToString ("G", CultureInfo.InvariantCulture), "A06");
+               Assert.AreEqual("10/27/1996 03:00:00", d2.End.ToString ("G", CultureInfo.InvariantCulture), "A07");
                Assert.AreEqual(36000000000L, d2.Delta.Ticks, "A08");
        
                DateTime d3 = new DateTime (2002,2,25);
@@ -46,6 +46,11 @@ public class TimeZoneTest {
                Assert.AreEqual(36000000000L, t1.GetUtcOffset (d3).Ticks, "A12");
                Assert.AreEqual(72000000000L, t1.GetUtcOffset (d4).Ticks, "A13");
                Assert.AreEqual(36000000000L, t1.GetUtcOffset (d5).Ticks, "A14");
+
+               // Test TimeZone methods with UTC DateTime in DST.
+               DateTime d6 = d4.ToUniversalTime ();
+               Assert.AreEqual(false, t1.IsDaylightSavingTime (d6), "A15");
+               Assert.AreEqual(0, t1.GetUtcOffset (d6).Ticks, "A16");
        }
 
        private void EST (TimeZone t1) 
@@ -55,25 +60,31 @@ public class TimeZoneTest {
                //Assert.AreEqual("Eastern Daylight Time", t1.DaylightName, "B02");
 
                DaylightTime d1 = t1.GetDaylightChanges (2002);
-               Assert.AreEqual("04/07/2002 02:00:00", d1.Start.ToString ("G"), "B03");
-               Assert.AreEqual("10/27/2002 02:00:00", d1.End.ToString ("G"), "B04");
+               Assert.AreEqual("04/07/2002 02:00:00", d1.Start.ToString ("G", CultureInfo.InvariantCulture), "B03");
+               Assert.AreEqual("10/27/2002 02:00:00", d1.End.ToString ("G", CultureInfo.InvariantCulture), "B04");
                Assert.AreEqual(36000000000L, d1.Delta.Ticks, "B05");
 
                DaylightTime d2 = t1.GetDaylightChanges (1996);
-               Assert.AreEqual("04/07/1996 02:00:00", d2.Start.ToString ("G"), "B06");
-               Assert.AreEqual("10/27/1996 02:00:00", d2.End.ToString ("G"), "B07");
+               Assert.AreEqual("04/07/1996 02:00:00", d2.Start.ToString ("G", CultureInfo.InvariantCulture), "B06");
+               Assert.AreEqual("10/27/1996 02:00:00", d2.End.ToString ("G", CultureInfo.InvariantCulture), "B07");
                Assert.AreEqual(36000000000L, d2.Delta.Ticks, "B08");
 
                DateTime d3 = new DateTime (2002,2,25);
                Assert.AreEqual(false, t1.IsDaylightSavingTime (d3), "B09");
                DateTime d4 = new DateTime (2002,4,8);
                Assert.AreEqual(true, t1.IsDaylightSavingTime (d4), "B10");
+               
                DateTime d5 = new DateTime (2002,11,4);
                Assert.AreEqual(false, t1.IsDaylightSavingTime (d5), "B11");
 
                Assert.AreEqual(-180000000000L, t1.GetUtcOffset (d3).Ticks, "B12");
                Assert.AreEqual(-144000000000L, t1.GetUtcOffset (d4).Ticks, "B13");
                Assert.AreEqual(-180000000000L, t1.GetUtcOffset (d5).Ticks, "B14");
+
+               // Test TimeZone methods with UTC DateTime in DST.
+               DateTime d6 = d4.ToUniversalTime ();
+               Assert.AreEqual(false, t1.IsDaylightSavingTime (d6), "B15");
+               Assert.AreEqual(0, t1.GetUtcOffset (d6).Ticks, "B16");
        }
 
        private void TST (TimeZone t1) 
@@ -101,13 +112,13 @@ public class TimeZoneTest {
                Assert.IsTrue("BST" == t1.DaylightName || "IST" == t1.DaylightName, "D02");
        
                DaylightTime d1 = t1.GetDaylightChanges (2002);
-               Assert.AreEqual("03/31/2002 01:00:00", d1.Start.ToString ("G"), "D03");
-               Assert.AreEqual("10/27/2002 02:00:00", d1.End.ToString ("G"), "D04");
+               Assert.AreEqual("03/31/2002 01:00:00", d1.Start.ToString ("G", CultureInfo.InvariantCulture), "D03");
+               Assert.AreEqual("10/27/2002 02:00:00", d1.End.ToString ("G", CultureInfo.InvariantCulture), "D04");
                Assert.AreEqual(36000000000L, d1.Delta.Ticks, "D05");
        
                DaylightTime d2 = t1.GetDaylightChanges (1996);
-               Assert.AreEqual("03/31/1996 01:00:00", d2.Start.ToString ("G"), "D06");
-               Assert.AreEqual("10/27/1996 02:00:00", d2.End.ToString ("G"), "D07");
+               Assert.AreEqual("03/31/1996 01:00:00", d2.Start.ToString ("G", CultureInfo.InvariantCulture), "D06");
+               Assert.AreEqual("10/27/1996 02:00:00", d2.End.ToString ("G", CultureInfo.InvariantCulture), "D07");
                Assert.AreEqual(36000000000L, d2.Delta.Ticks, "D08");
        
                DateTime d3 = new DateTime (2002,2,25);
@@ -120,6 +131,11 @@ public class TimeZoneTest {
                Assert.AreEqual(0L, t1.GetUtcOffset (d3).Ticks, "D12");
                Assert.AreEqual(36000000000L, t1.GetUtcOffset (d4).Ticks, "D13");
                Assert.AreEqual(0L, t1.GetUtcOffset (d5).Ticks, "D14");
+
+               // Test TimeZone methods with UTC DateTime in DST.
+               DateTime d6 = d4.ToUniversalTime ();
+               Assert.AreEqual(false, t1.IsDaylightSavingTime (d6), "D15");
+               Assert.AreEqual(0, t1.GetUtcOffset (d6).Ticks, "D16");
        }
 
        private void NZST(TimeZone t1) {
@@ -127,13 +143,13 @@ public class TimeZoneTest {
                Assert.AreEqual("NZDT", t1.DaylightName, "E02");
 
                DaylightTime d1 = t1.GetDaylightChanges (2013);
-               Assert.AreEqual("09/29/2013 02:00:00", d1.Start.ToString ("G"), "E03");
-               Assert.AreEqual("04/07/2013 03:00:00", d1.End.ToString ("G"), "E04");
+               Assert.AreEqual("09/29/2013 02:00:00", d1.Start.ToString ("G", CultureInfo.InvariantCulture), "E03");
+               Assert.AreEqual("04/07/2013 03:00:00", d1.End.ToString ("G", CultureInfo.InvariantCulture), "E04");
                Assert.AreEqual(36000000000L, d1.Delta.Ticks, "E05");
 
                DaylightTime d2 = t1.GetDaylightChanges (2001);
-               Assert.AreEqual("10/07/2001 02:00:00", d2.Start.ToString ("G"), "E06");
-               Assert.AreEqual("03/18/2001 03:00:00", d2.End.ToString ("G"), "E07");
+               Assert.AreEqual("10/07/2001 02:00:00", d2.Start.ToString ("G", CultureInfo.InvariantCulture), "E06");
+               Assert.AreEqual("03/18/2001 03:00:00", d2.End.ToString ("G", CultureInfo.InvariantCulture), "E07");
                Assert.AreEqual(36000000000L, d2.Delta.Ticks, "E08");
 
                DateTime d3 = new DateTime(2013,02,15);
@@ -146,10 +162,14 @@ public class TimeZoneTest {
                Assert.AreEqual(36000000000L /*hour*/ * 13L, t1.GetUtcOffset (d3).Ticks, "E12");
                Assert.AreEqual(36000000000L /*hour*/ * 12L, t1.GetUtcOffset (d4).Ticks, "E13");
                Assert.AreEqual(36000000000L /*hour*/ * 13L, t1.GetUtcOffset (d5).Ticks, "E14");
+
+               // Test TimeZone methods with UTC DateTime in DST.
+               DateTime d6 = d5.ToUniversalTime ();
+               Assert.AreEqual(false, t1.IsDaylightSavingTime (d6), "E15");
+               Assert.AreEqual(0, t1.GetUtcOffset (d6).Ticks, "E16");
        }
 
        [Test]
-       [Culture ("")]
        public void TestCtors ()
        {
                TimeZone t1 = TimeZone.CurrentTimeZone;
index ec4396cfb18c6c26190ba84755baafa81c477841..f80a9c00949bb4cf7f1e101a31513cfe884290ab 100644 (file)
@@ -129,9 +129,6 @@ ICALL(CONSOLE_3, "SetBreak", ves_icall_System_ConsoleDriver_SetBreak )
 ICALL(CONSOLE_4, "SetEcho", ves_icall_System_ConsoleDriver_SetEcho )
 ICALL(CONSOLE_5, "TtySetup", ves_icall_System_ConsoleDriver_TtySetup )
 
-ICALL_TYPE(TZONE, "System.CurrentSystemTimeZone", TZONE_1)
-ICALL(TZONE_1, "GetTimeZoneData", ves_icall_System_CurrentSystemTimeZone_GetTimeZoneData)
-
 ICALL_TYPE(DTIME, "System.DateTime", DTIME_1)
 ICALL(DTIME_1, "GetSystemTimeAsFileTime", mono_100ns_datetime)
 
index 62040ceb6d928807e6769975538f9e9400d2c25f..6ac14185a1b611f007ed9488ef245e6c9dcdb8ba 100644 (file)
@@ -5613,257 +5613,6 @@ ves_icall_System_Delegate_SetMulticastInvoke (MonoDelegate *this)
        this->invoke_impl = mono_runtime_create_delegate_trampoline (this->object.vtable->klass);
 }
 
-/*
- * Magic number to convert a time which is relative to
- * Jan 1, 1970 into a value which is relative to Jan 1, 0001.
- */
-#define        EPOCH_ADJUST    ((guint64)62135596800LL)
-
-/*
- * Magic number to convert FILETIME base Jan 1, 1601 to DateTime - base Jan, 1, 0001
- */
-#define FILETIME_ADJUST ((guint64)504911232000000000LL)
-
-#ifdef HOST_WIN32
-/* convert a SYSTEMTIME which is of the form "last thursday in october" to a real date */
-static void
-convert_to_absolute_date(SYSTEMTIME *date)
-{
-#define IS_LEAP(y) ((y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0))
-       static int days_in_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-       static int leap_days_in_month[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-       /* from the calendar FAQ */
-       int a = (14 - date->wMonth) / 12;
-       int y = date->wYear - a;
-       int m = date->wMonth + 12 * a - 2;
-       int d = (1 + y + y/4 - y/100 + y/400 + (31*m)/12) % 7;
-
-       /* d is now the day of the week for the first of the month (0 == Sunday) */
-
-       int day_of_week = date->wDayOfWeek;
-
-       /* set day_in_month to the first day in the month which falls on day_of_week */    
-       int day_in_month = 1 + (day_of_week - d);
-       if (day_in_month <= 0)
-               day_in_month += 7;
-
-       /* wDay is 1 for first weekday in month, 2 for 2nd ... 5 means last - so work that out allowing for days in the month */
-       date->wDay = day_in_month + (date->wDay - 1) * 7;
-       if (date->wDay > (IS_LEAP(date->wYear) ? leap_days_in_month[date->wMonth - 1] : days_in_month[date->wMonth - 1]))
-               date->wDay -= 7;
-}
-#endif
-
-#ifndef HOST_WIN32
-/*
- * Return's the offset from GMT of a local time.
- * 
- *  tm is a local time
- *  t  is the same local time as seconds.
- */
-static int 
-gmt_offset(struct tm *tm, time_t t)
-{
-#if defined (HAVE_TM_GMTOFF)
-       return tm->tm_gmtoff;
-#else
-       struct tm g;
-       time_t t2;
-       g = *gmtime(&t);
-       g.tm_isdst = tm->tm_isdst;
-       t2 = mktime(&g);
-       return (int)difftime(t, t2);
-#endif
-}
-#endif
-/*
- * This is heavily based on zdump.c from glibc 2.2.
- *
- *  * data[0]:  start of daylight saving time (in DateTime ticks).
- *  * data[1]:  end of daylight saving time (in DateTime ticks).
- *  * data[2]:  utcoffset (in TimeSpan ticks).
- *  * data[3]:  additional offset when daylight saving (in TimeSpan ticks).
- *  * name[0]:  name of this timezone when not daylight saving.
- *  * name[1]:  name of this timezone when daylight saving.
- *
- *  FIXME: This only works with "standard" Unix dates (years between 1900 and 2100) while
- *         the class library allows years between 1 and 9999.
- *
- *  Returns true on success and zero on failure.
- */
-ICALL_EXPORT guint32
-ves_icall_System_CurrentSystemTimeZone_GetTimeZoneData (guint32 year, MonoArray **data, MonoArray **names)
-{
-#ifndef HOST_WIN32
-       MonoDomain *domain = mono_domain_get ();
-       struct tm start, tt;
-       time_t t;
-
-       long int gmtoff, gmtoff_after, gmtoff_st, gmtoff_ds;
-       int day, transitioned;
-       char tzone [64];
-
-       gmtoff_st = gmtoff_ds = transitioned = 0;
-
-       MONO_CHECK_ARG_NULL (data, 0);
-       MONO_CHECK_ARG_NULL (names, 0);
-
-       mono_gc_wbarrier_generic_store (data, (MonoObject*) mono_array_new (domain, mono_defaults.int64_class, 4));
-       mono_gc_wbarrier_generic_store (names, (MonoObject*) mono_array_new (domain, mono_defaults.string_class, 2));
-
-       /* 
-        * no info is better than crashing: we'll need our own tz data
-        * to make this work properly, anyway. The range is probably
-        * reduced to 1970 .. 2037 because that is what mktime is
-        * guaranteed to support (we get into an infinite loop
-        * otherwise).
-        */
-
-       memset (&start, 0, sizeof (start));
-
-       start.tm_mday = 1;
-       start.tm_year = year-1900;
-
-       t = mktime (&start);
-
-       if ((year < 1970) || (year > 2037) || (t == -1)) {
-               t = time (NULL);
-               tt = *localtime (&t);
-               strftime (tzone, sizeof (tzone), "%Z", &tt);
-               mono_array_setref ((*names), 0, mono_string_new (domain, tzone));
-               mono_array_setref ((*names), 1, mono_string_new (domain, tzone));
-               return 1;
-       }
-
-       gmtoff = gmt_offset (&start, t);
-
-       /* For each day of the year, calculate the tm_gmtoff. */
-       for (day = 0; day < 365 && transitioned < 2; day++) {
-
-               t += 3600*24;
-               tt = *localtime (&t);
-
-        gmtoff_after = gmt_offset(&tt, t);
-
-               /* Daylight saving starts or ends here. */
-               if (gmtoff_after != gmtoff) {
-                       struct tm tt1;
-                       time_t t1;
-
-                       /* Try to find the exact hour when daylight saving starts/ends. */
-                       t1 = t;
-                       do {
-                               t1 -= 3600;
-                               tt1 = *localtime (&t1);
-                       } while (gmt_offset (&tt1, t1) != gmtoff);
-
-                       /* Try to find the exact minute when daylight saving starts/ends. */
-                       do {
-                               t1 += 60;
-                               tt1 = *localtime (&t1);
-                       } while (gmt_offset (&tt1, t1) == gmtoff);
-                       t1+=gmtoff;
-                       strftime (tzone, sizeof (tzone), "%Z", &tt);
-                       
-                       /* Write data, if we're already in daylight saving, we're done. */
-                       if (tt.tm_isdst) {
-                               mono_array_setref ((*names), 1, mono_string_new (domain, tzone));
-                               mono_array_set ((*data), gint64, 0, ((gint64)t1 + EPOCH_ADJUST) * 10000000L);
-                               if (gmtoff_ds == 0) {
-                                       gmtoff_st = gmtoff;
-                                       gmtoff_ds = gmtoff_after;
-                               }
-                               transitioned++;
-                       } else {
-                               mono_array_setref ((*names), 0, mono_string_new (domain, tzone));
-                               mono_array_set ((*data), gint64, 1, ((gint64)t1 + EPOCH_ADJUST) * 10000000L);
-                               if (gmtoff_ds == 0) {
-                                       gmtoff_st = gmtoff_after;
-                                       gmtoff_ds = gmtoff;
-                               }
-                               transitioned++;
-                       }
-
-                       /* This is only set once when we enter daylight saving. */
-                       if (tt1.tm_isdst) {
-                               mono_array_set ((*data), gint64, 2, (gint64)gmtoff_st * 10000000L);
-                               mono_array_set ((*data), gint64, 3, (gint64)(gmtoff_ds - gmtoff_st) * 10000000L);
-                       }
-                       gmtoff = gmt_offset (&tt, t);
-               }
-       }
-
-       if (transitioned < 2) {
-               strftime (tzone, sizeof (tzone), "%Z", &tt);
-               mono_array_setref ((*names), 0, mono_string_new (domain, tzone));
-               mono_array_setref ((*names), 1, mono_string_new (domain, tzone));
-               mono_array_set ((*data), gint64, 0, 0);
-               mono_array_set ((*data), gint64, 1, 0);
-               mono_array_set ((*data), gint64, 2, (gint64) gmtoff * 10000000L);
-               mono_array_set ((*data), gint64, 3, 0);
-       }
-
-       return 1;
-#else
-       MonoDomain *domain = mono_domain_get ();
-       TIME_ZONE_INFORMATION tz_info;
-       FILETIME ft;
-       int i;
-       int err, tz_id;
-
-       tz_id = GetTimeZoneInformation (&tz_info);
-       if (tz_id == TIME_ZONE_ID_INVALID)
-               return 0;
-
-       MONO_CHECK_ARG_NULL (data, 0);
-       MONO_CHECK_ARG_NULL (names, 0);
-
-       mono_gc_wbarrier_generic_store (data, mono_array_new (domain, mono_defaults.int64_class, 4));
-       mono_gc_wbarrier_generic_store (names, mono_array_new (domain, mono_defaults.string_class, 2));
-
-       for (i = 0; i < 32; ++i)
-               if (!tz_info.DaylightName [i])
-                       break;
-       mono_array_setref ((*names), 1, mono_string_new_utf16 (domain, tz_info.DaylightName, i));
-       for (i = 0; i < 32; ++i)
-               if (!tz_info.StandardName [i])
-                       break;
-       mono_array_setref ((*names), 0, mono_string_new_utf16 (domain, tz_info.StandardName, i));
-
-       if ((year <= 1601) || (year > 30827)) {
-               /*
-                * According to MSDN, the MS time functions can't handle dates outside
-                * this interval.
-                */
-               return 1;
-       }
-
-       /* even if the timezone has no daylight savings it may have Bias (e.g. GMT+13 it seems) */
-       if (tz_id != TIME_ZONE_ID_UNKNOWN) {
-               tz_info.StandardDate.wYear = year;
-               convert_to_absolute_date(&tz_info.StandardDate);
-               err = SystemTimeToFileTime (&tz_info.StandardDate, &ft);
-               //g_assert(err);
-               if (err == 0)
-                       return 0;
-               
-               mono_array_set ((*data), gint64, 1, FILETIME_ADJUST + (((guint64)ft.dwHighDateTime<<32) | ft.dwLowDateTime));
-               tz_info.DaylightDate.wYear = year;
-               convert_to_absolute_date(&tz_info.DaylightDate);
-               err = SystemTimeToFileTime (&tz_info.DaylightDate, &ft);
-               //g_assert(err);
-               if (err == 0)
-                       return 0;
-               
-               mono_array_set ((*data), gint64, 0, FILETIME_ADJUST + (((guint64)ft.dwHighDateTime<<32) | ft.dwLowDateTime));
-       }
-       mono_array_set ((*data), gint64, 2, (tz_info.Bias + tz_info.StandardBias) * -600000000LL);
-       mono_array_set ((*data), gint64, 3, (tz_info.DaylightBias - tz_info.StandardBias) * -600000000LL);
-
-       return 1;
-#endif
-}
-
 /* System.Buffer */
 
 static inline gint32