2002-06-27 Martin Baulig <martin@gnome.org>
[mono.git] / mcs / class / corlib / System / TimeZone.cs
index 0e669b21adbf9aa4817257144024e2df3c070363..ce77e0d3d3f99b8965832693c6e8f903ad7479b4 100644 (file)
@@ -3,12 +3,14 @@
 //
 // Author: Duncan Mak (duncan@ximian.com)
 //        Ajay Kumar Dwivedi (adwiv@yahoo.com)
+//         Martin Baulig (martin@gnome.org)
 //
 // (C) Ximian, Inc.
 //
 
 using System.Collections;
 using System.Globalization;
+using System.Runtime.CompilerServices;
 
 namespace System {
        
@@ -51,26 +53,34 @@ namespace System {
 
                public virtual bool IsDaylightSavingTime (DateTime time)
                {
-                       int currentYear = CultureInfo.CurrentCulture.Calendar.GetYear (time);
-                       DaylightTime daylight = GetDaylightChanges (currentYear);
-
-                       return IsDaylightSavingTime (time, daylight);
+                       return IsDaylightSavingTime (time, GetDaylightChanges (time.Year));
                }
 
-               public virtual bool IsDaylightSavingTime (DateTime time, DaylightTime daylightTimes)
-               {
+               public static bool IsDaylightSavingTime (DateTime time, DaylightTime daylightTimes)
+                {
                        if (daylightTimes == null)
-                               throw new ArgumentNullException ("daylightTimes is null.");
-
-                       if (daylightTimes.Delta == TimeSpan.Zero)
-                               return false; 
-
-                       if ((daylightTimes.Start <= time) && (time < daylightTimes.End))
-                               return true;
-                       else // time doesn't not fall in the span of daylightTimes
-                               return false;
-               }
+                                throw new ArgumentNullException ("daylightTimes");
+
+                        // If Start == End, then DST is off
+                        if (daylightTimes.Start.Ticks == daylightTimes.End.Ticks)
+                                return false;
+
+                       //We are in the northern hemisphere.                           
+                       if (daylightTimes.Start.Ticks < daylightTimes.End.Ticks) {
+                                if (daylightTimes.Start.Ticks < time.Ticks
+                                   && daylightTimes.End.Ticks > time.Ticks)
+                                        return true; // time lies between Start and End
+
+                       } else {  // We are in the southern hemisphere.
+                               if (time.Year == daylightTimes.Start.Year && time.Year == daylightTimes.End.Year)
+                                        if (time.Ticks < daylightTimes.End.Ticks
+                                           || time.Ticks > daylightTimes.Start.Ticks)
+                                                return true; // time is less than End OR more than Start 
+                        }
 
+                       return false;
+                }
+               
                public virtual DateTime ToLocalTime (DateTime time)
                {
                        return time + GetUtcOffset (time);
@@ -97,11 +107,46 @@ namespace System {
                 // the offset when daylightsaving is on.
                 private static TimeSpan utcOffsetWithDLS;
 
+               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);
+
                // Constructor
-               [MonoTODO ("Add internal calls to initialize the fields")]
                internal CurrentTimeZone ()
                        : base ()
                {
+                       Int64[] data;
+                       string[] names;
+
+                       DateTime now = new DateTime(DateTime.GetNow ());                        
+                       if (!GetTimeZoneData (now.Year, out data, out names))
+                               throw new NotSupportedException (Locale.GetText ("Can't get timezone name"));
+
+                       standardName = Locale.GetText (names[(int)TimeZoneNames.StandardNameIdx]);
+                       daylightName = Locale.GetText (names[(int)TimeZoneNames.DaylightNameIdx]);
+
+                       utcOffsetWithOutDLS = new TimeSpan (data[(int)TimeZoneData.UtcOffsetIdx]);
+                       utcOffsetWithDLS = new TimeSpan (data[(int)TimeZoneData.UtcOffsetIdx] + data[(int)TimeZoneData.AdditionalDaylightOffsetIdx]);
                }
 
                // Properties
@@ -123,16 +168,22 @@ namespace System {
                                 throw new ArgumentOutOfRangeException (year + " is not in a range between 1 and 9999.");
 
                         if (daylightCache [year] == null) {
-                                //TODO: do something and put the DaylightTime corresponding to the time in cache.
-                                DaylightTime dlt = new DaylightTime (new DateTime (0),
-                                                    new DateTime (0), new TimeSpan (0));
+                               Int64[] data;
+                               string[] names;
+
+                               if (!GetTimeZoneData (year, out data, out names))
+                                       throw new ArgumentException (Locale.GetText ("Can't get timezone data for " + year));
+
+                               DaylightTime dlt = new DaylightTime (new DateTime (data[(int)TimeZoneData.DaylightSavingStartIdx]),
+                                                                    new DateTime (data[(int)TimeZoneData.DaylightSavingEndIdx]),
+                                                                    new TimeSpan (data[(int)TimeZoneData.AdditionalDaylightOffsetIdx]));
                                daylightCache.Add (year, dlt);
                         }
 
                        return (DaylightTime) daylightCache [year];
                 }
 
-               public override TimeSpan GetUtcOffset(DateTime time)
+               public override TimeSpan GetUtcOffset (DateTime time)
                {
                         if (IsDaylightSavingTime (time))
                                 return utcOffsetWithDLS;