Merge pull request #1321 from esdrubal/currentsystemtimezone
authorMarcos Henrich <marcoshenrich@gmail.com>
Tue, 28 Oct 2014 18:18:54 +0000 (18:18 +0000)
committerMarcos Henrich <marcoshenrich@gmail.com>
Tue, 28 Oct 2014 18:18:54 +0000 (18:18 +0000)
CurrentSystemTimeZone.GetUtcOffset now supports multiple DST periods.

mcs/class/System.Core/System/TimeZoneInfo.AdjustmentRule.cs
mcs/class/System.Core/System/TimeZoneInfo.Serialization.cs
mcs/class/System.Core/System/TimeZoneInfo.TransitionTime.cs
mcs/class/System.Core/System/TimeZoneInfo.cs
mcs/class/System.Core/Test/System/TimeZoneInfoTest.cs
mcs/class/corlib/DateTime.Now_Test.sh [new file with mode: 0755]
mcs/class/corlib/System/InvalidTimeZoneException.cs
mcs/class/corlib/System/TimeZone.cs
mcs/class/corlib/System/TimeZoneNotFoundException.cs

index 637d0c400dffd8384193b9dd29ed72f867654d6c..37f21464dcfc9067d489e354a70b857907755364 100644 (file)
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#if (INSIDE_CORLIB && NET_4_0) || (!INSIDE_CORLIB && (NET_3_5 && !NET_4_0 && !MOBILE))
+#if INSIDE_CORLIB || (NET_3_5 && !NET_4_0 && !MOBILE)
 using System.Runtime.CompilerServices;
 using System.Runtime.Serialization;
 
 namespace System
 {
-       public sealed partial class TimeZoneInfo {
+#if NET_4_0 || !INSIDE_CORLIB
+       public
+#endif
+       sealed partial class TimeZoneInfo {
                [SerializableAttribute]
 #if MOBILE
        [TypeForwardedFrom (Consts.AssemblySystem_Core)]
index 22aa38c5fa62f95c7328adc53b07c98804f25225..3a7da39ec7fe52baad83a1d0c5543e9a3658787c 100644 (file)
@@ -24,7 +24,7 @@
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#if (INSIDE_CORLIB && NET_4_0) || (!INSIDE_CORLIB && (NET_3_5 && !NET_4_0 && !MOBILE))
+#if INSIDE_CORLIB || (NET_3_5 && !NET_4_0 && !MOBILE)
 
 using System.Collections.Generic;
 using System.Globalization;
@@ -33,7 +33,10 @@ using System.Text;
 
 namespace System
 {
-       public partial class TimeZoneInfo
+#if NET_4_0 || !INSIDE_CORLIB
+       public
+#endif
+       partial class TimeZoneInfo
        {
                public static TimeZoneInfo FromSerializedString (string source)
                {
index d57df150f0554bb1d318dd787d2b71225cc726f6..719bb9d51f382c4be9c8277ac17126df2ec8502c 100644 (file)
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#if (INSIDE_CORLIB && NET_4_0) || (!INSIDE_CORLIB && (NET_3_5 && !NET_4_0 && !MOBILE))
+#if INSIDE_CORLIB || (NET_3_5 && !NET_4_0 && !MOBILE)
 
 using System.Runtime.CompilerServices;
 using System.Runtime.Serialization;
 
 namespace System
 {
-       public sealed partial class TimeZoneInfo 
+#if NET_4_0 || !INSIDE_CORLIB
+       public
+#endif
+       sealed partial class TimeZoneInfo
        {
                [SerializableAttribute]
 #if MOBILE
index 9994b125c79a47e7e8d4b501a477817cad94d4e7..f6fa19c0d34e182fd43b44a98bfddb524e98cb96 100644 (file)
@@ -35,7 +35,7 @@ using System.Threading;
 
 [assembly:TypeForwardedTo (typeof(TimeZoneInfo))]
 
-#elif (INSIDE_CORLIB && NET_4_0) || (!INSIDE_CORLIB && (NET_3_5 && !NET_4_0 && !MOBILE))
+#elif INSIDE_CORLIB || (NET_3_5 && !NET_4_0 && !MOBILE)
 
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
@@ -57,7 +57,10 @@ namespace System
        [TypeForwardedFrom (Consts.AssemblySystemCore_3_5)]
 #endif
        [SerializableAttribute]
-       public sealed partial class TimeZoneInfo : IEquatable<TimeZoneInfo>, ISerializable, IDeserializationCallback
+#if NET_4_0 || !INSIDE_CORLIB
+       public
+#endif
+       sealed partial class TimeZoneInfo : IEquatable<TimeZoneInfo>, ISerializable, IDeserializationCallback
        {
                TimeSpan baseUtcOffset;
                public TimeSpan BaseUtcOffset {
@@ -100,6 +103,11 @@ namespace System
                        }
                }
 
+               /*
+                       TimeZone transitions are stored when there is a change on the base offset.
+               */
+               private List<KeyValuePair<DateTime, TimeType>> transitions;
+
                static TimeZoneInfo CreateLocal ()
                {
 #if MONODROID
@@ -109,6 +117,17 @@ namespace System
                                return BuildFromStream ("Local", stream);
                        }
 #elif LIBC
+                       var tz = Environment.GetEnvironmentVariable ("TZ");
+                       if (tz != null) {
+                               if (tz == String.Empty)
+                                       return Utc;
+                               try {
+                                       return FindSystemTimeZoneByFileName (tz, Path.Combine (TimeZoneDirectory, tz));
+                               } catch {
+                                       return Utc;
+                               }
+                       }
+
                        try {
                                return FindSystemTimeZoneByFileName ("Local", "/etc/localtime");        
                        } catch {
@@ -332,8 +351,7 @@ namespace System
                        if (dateTime.Kind == DateTimeKind.Utc)
                                return dateTime;
 
-                       //FIXME: do not rely on DateTime implementation !
-                       return DateTime.SpecifyKind (dateTime.ToUniversalTime (), DateTimeKind.Utc);
+                       return ConvertTimeToUtc (dateTime, TimeZoneInfo.Local);
                }
 
                public static DateTime ConvertTimeToUtc (DateTime dateTime, TimeZoneInfo sourceTimeZone)
@@ -350,15 +368,9 @@ namespace System
                        if (sourceTimeZone.IsInvalidTime (dateTime))
                                throw new ArgumentException ("dateTime parameter is an invalid time");
 
-                       if (dateTime.Kind == DateTimeKind.Utc && sourceTimeZone == TimeZoneInfo.Utc)
-                               return dateTime;
-
                        if (dateTime.Kind == DateTimeKind.Utc)
                                return dateTime;
 
-                       if (dateTime.Kind == DateTimeKind.Local)
-                               return ConvertTimeToUtc (dateTime);
-
                        if (sourceTimeZone.IsAmbiguousTime (dateTime) || !sourceTimeZone.IsDaylightSavingTime (dateTime))
                                return DateTime.SpecifyKind (dateTime - sourceTimeZone.BaseUtcOffset, DateTimeKind.Utc);
                        else {
@@ -684,13 +696,8 @@ namespace System
 
                public TimeSpan GetUtcOffset (DateTime dateTime)
                {
-                       if (IsDaylightSavingTime (dateTime)) {
-                               AdjustmentRule rule = GetApplicableRule (dateTime);
-                               if (rule != null)
-                                       return BaseUtcOffset + rule.DaylightDelta;
-                       }
-                       
-                       return BaseUtcOffset;
+                       bool isDST;
+                       return GetUtcOffset (dateTime, out isDST);
                }
 
                public TimeSpan GetUtcOffset (DateTimeOffset dateTimeOffset)
@@ -698,6 +705,82 @@ namespace System
                        throw new NotImplementedException ();
                }
 
+               private TimeSpan GetUtcOffset (DateTime dateTime, out bool isDST)
+               {
+                       isDST = false;
+
+                       TimeZoneInfo tz = this;
+                       if (dateTime.Kind == DateTimeKind.Utc)
+                               tz = TimeZoneInfo.Utc;
+
+                       if (dateTime.Kind == DateTimeKind.Local)
+                               tz = TimeZoneInfo.Local;
+
+                       bool isTzDst;
+                       var tzOffset = GetUtcOffset (dateTime, tz, out isTzDst);
+
+                       if (tz == this) {
+                               isDST = isTzDst;
+                               return tzOffset;
+                       }
+
+                       var utcTicks = dateTime.Ticks - tzOffset.Ticks;
+                       if (utcTicks < 0 || utcTicks > DateTime.MaxValue.Ticks)
+                               return BaseUtcOffset;
+
+                       var utcDateTime = new DateTime (utcTicks, DateTimeKind.Utc);
+
+                       return GetUtcOffset (utcDateTime, this, out isDST);
+               }
+
+               private static TimeSpan GetUtcOffset (DateTime dateTime, TimeZoneInfo tz, out bool isDST)
+               {
+                       if (dateTime.Kind == DateTimeKind.Local && tz != TimeZoneInfo.Local)
+                               throw new Exception ();
+
+                       isDST = false;
+
+                       if (tz == TimeZoneInfo.Utc)
+                               return TimeSpan.Zero;
+
+                       TimeSpan offset;
+                       if (tz.TryGetTransitionOffset(dateTime, out offset, out isDST))
+                               return offset;
+
+                       if (dateTime.Kind == DateTimeKind.Utc) {
+                               var utcRule = tz.GetApplicableRule (dateTime);
+                               if (utcRule != null && tz.IsInDST (utcRule, dateTime)) {
+                                       isDST = true;
+                                       return tz.BaseUtcOffset + utcRule.DaylightDelta;
+                               }
+
+                               return tz.BaseUtcOffset;
+                       }
+
+                       var stdTicks = dateTime.Ticks - tz.BaseUtcOffset.Ticks;
+                       if (stdTicks < 0 || stdTicks > DateTime.MaxValue.Ticks)
+                               return tz.BaseUtcOffset;
+
+                       var stdUtcDateTime = new DateTime (stdTicks, DateTimeKind.Utc);
+                       var tzRule = tz.GetApplicableRule (stdUtcDateTime);
+
+                       DateTime dstUtcDateTime = DateTime.MinValue;
+                       if (tzRule != null) {
+                               var dstTicks = stdUtcDateTime.Ticks - tzRule.DaylightDelta.Ticks;
+                               if (dstTicks < 0 || dstTicks > DateTime.MaxValue.Ticks)
+                                       return tz.BaseUtcOffset;
+
+                               dstUtcDateTime = new DateTime (dstTicks, DateTimeKind.Utc);
+                       }
+
+                       if (tzRule != null && tz.IsInDST (tzRule, stdUtcDateTime) && tz.IsInDST (tzRule, dstUtcDateTime)) {
+                               isDST = true;
+                               return tz.BaseUtcOffset + tzRule.DaylightDelta;
+                       }
+
+                       return tz.BaseUtcOffset;
+               }
+
                public bool HasSameRules (TimeZoneInfo other)
                {
                        if (other == null)
@@ -752,6 +835,16 @@ namespace System
                        throw new NotImplementedException ();
                }
 
+               private bool IsInDST (AdjustmentRule rule, DateTime dateTime)
+               {
+                       // Check whether we're in the dateTime year's DST period
+                       if (IsInDSTForYear (rule, dateTime, dateTime.Year))
+                               return true;
+
+                       // We might be in the dateTime previous year's DST period
+                       return IsInDSTForYear (rule, dateTime, dateTime.Year - 1);
+               }
+
                bool IsInDSTForYear (AdjustmentRule rule, DateTime dateTime, int year)
                {
                        DateTime DST_start = TransitionPoint (rule.DaylightTransitionStart, year);
@@ -774,25 +867,11 @@ namespace System
                        
                        if (!SupportsDaylightSavingTime)
                                return false;
-                       
-                       //FIXME: do not rely on DateTime implementation !
-                       if ((dateTime.Kind == DateTimeKind.Local || dateTime.Kind == DateTimeKind.Unspecified) && this == TimeZoneInfo.Local)
-                               return dateTime.IsDaylightSavingTime ();
-                       
-                       //FIXME: do not rely on DateTime implementation !
-                       if (dateTime.Kind == DateTimeKind.Local && this != TimeZoneInfo.Utc)
-                               return IsDaylightSavingTime (DateTime.SpecifyKind (dateTime.ToUniversalTime (), DateTimeKind.Utc));
-                       
-                       AdjustmentRule rule = GetApplicableRule (dateTime.Date);
-                       if (rule == null)
-                               return false;
 
-                       // Check whether we're in the dateTime year's DST period
-                       if (IsInDSTForYear (rule, dateTime, dateTime.Year))
-                               return true;
+                       bool isDst;
+                       GetUtcOffset (dateTime, out isDst);
 
-                       // We might be in the dateTime previous year's DST period
-                       return IsInDSTForYear (rule, dateTime, dateTime.Year - 1);
+                       return isDst;
                }
 
                public bool IsDaylightSavingTime (DateTimeOffset dateTimeOffset)
@@ -969,6 +1048,40 @@ namespace System
                        return null;
                }
 
+               private bool TryGetTransitionOffset (DateTime dateTime, out TimeSpan offset,out bool isDst)
+               {
+                       offset = BaseUtcOffset;
+                       isDst = false;
+
+                       if (transitions == null)
+                               return false;
+
+                       //Transitions are always in standard time
+                       DateTime date = dateTime;
+
+                       if (dateTime.Kind == DateTimeKind.Local && this != TimeZoneInfo.Local)
+                               date = date.ToUniversalTime () + BaseUtcOffset;
+
+                       if (dateTime.Kind == DateTimeKind.Utc && this != TimeZoneInfo.Utc)
+                               date = date + BaseUtcOffset;
+
+                       for (var i =  transitions.Count - 1; i >= 0; i--) {
+                               var pair = transitions [i];
+                               DateTime ttime = pair.Key;
+                               TimeType ttype = pair.Value;
+
+                               if (ttime > date)
+                                       continue;
+
+                               offset =  new TimeSpan (0, 0, ttype.Offset);
+                               isDst = ttype.IsDst;
+
+                               return true;
+                       }
+
+                       return false;
+               }
+
                private static DateTime TransitionPoint (TransitionTime transition, int year)
                {
                        if (transition.IsFixedDateRule)
@@ -1059,6 +1172,7 @@ namespace System
                        bool dst_observed = false;
                        DateTime dst_start = DateTime.MinValue;
                        List<AdjustmentRule> adjustmentRules = new List<AdjustmentRule> ();
+                       bool storeTransition = false;
 
                        for (int i = 0; i < transitions.Count; i++) {
                                var pair = transitions [i];
@@ -1069,6 +1183,8 @@ namespace System
                                                standardDisplayName = ttype.Name;
                                                daylightDisplayName = null;
                                                baseUtcOffset = new TimeSpan (0, 0, ttype.Offset);
+                                               if (adjustmentRules.Count > 0) // We ignore AdjustmentRules but store transitions.
+                                                       storeTransition = true;
                                                adjustmentRules = new List<AdjustmentRule> ();
                                                dst_observed = false;
                                        }
@@ -1110,16 +1226,22 @@ namespace System
                                }
                        }
 
-                       if (adjustmentRules.Count == 0) {
+                       TimeZoneInfo tz;
+                       if (adjustmentRules.Count == 0 && !storeTransition) {
                                TimeType t = (TimeType)time_types [0];
                                if (standardDisplayName == null) {
                                        standardDisplayName = t.Name;
                                        baseUtcOffset = new TimeSpan (0, 0, t.Offset);
                                }
-                               return CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName);
+                               tz = CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName);
                        } else {
-                               return CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName, daylightDisplayName, ValidateRules (adjustmentRules).ToArray ());
+                               tz = CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName, daylightDisplayName, ValidateRules (adjustmentRules).ToArray ());
                        }
+
+                       if (storeTransition)
+                               tz.transitions = transitions;
+
+                       return tz;
                }
 
                static Dictionary<int, string> ParseAbbreviations (byte [] buffer, int index, int count)
index f6ea66e98c69321b32c060c184913b9fb3a832fe..c3972e747c17df0e79a2f83a92bac99c8667f98a 100644 (file)
@@ -232,7 +232,7 @@ namespace MonoTests.System
                                DateTime afterDST = new DateTime (2007, 10, 28, 2, 0, 0, DateTimeKind.Unspecified);
                                Assert.IsFalse (london.IsDaylightSavingTime (beforeDST), "Just before DST");
                                Assert.IsTrue (london.IsDaylightSavingTime (startDST), "the first seconds of DST");
-                               Assert.IsTrue (london.IsDaylightSavingTime (endDST), "The last seconds of DST");
+                               Assert.IsFalse (london.IsDaylightSavingTime (endDST), "The last seconds of DST");
                                Assert.IsFalse (london.IsDaylightSavingTime (afterDST), "Just after DST");
                        }
                
@@ -804,6 +804,143 @@ namespace MonoTests.System
                                Assert.IsTrue (london.Equals (deserialized));
                        }
                }
+
+               [TestFixture]
+               public class MultipleDaylightSavingTimeTests {
+                       private TimeZoneInfo cairo;
+                       private DateTime dst1Start;
+                       private DateTime dst1End;
+                       private DateTime dst2Start;
+                       private DateTime dst2End;
+
+                       private TimeSpan baseUtcOffset;
+                       private TimeSpan dstUtcOffset;
+                       private TimeSpan dstOffset;
+
+                       [SetUp]
+                       public void CreateTimeZones ()
+                       {
+                               /*
+                               From 1/1/2014 12:00:00 AM to 6/30/2014 12:00:00 AM
+                                       Delta: 01:00:00
+                                       Begins at 12:00 AM on 16 May
+                                       Ends at 1:00 AM on 29 June
+                               From 7/1/2014 12:00:00 AM to 12/31/2014 12:00:00 AM
+                                       Delta: 01:00:00
+                                       Begins at 12:00 AM on 29 July
+                                       Ends at 12:00 AM on 26 September
+                               */
+                               dst1Start = new DateTime (2014, 5, 16);
+                               dst1End = new DateTime (2014, 6, 29);
+                               dst2Start = new DateTime (2014, 7, 29);
+                               dst2End = new DateTime (2014, 9, 26);
+
+                               baseUtcOffset = new TimeSpan (2, 0, 0);
+                               dstUtcOffset = new TimeSpan (3, 0, 0);
+                               dstOffset = dstUtcOffset - baseUtcOffset;
+
+                               var rule1 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (
+                                       new DateTime (2014, 1, 1), new DateTime (2014, 6, 30), dstOffset,
+                                       CreateFixedDateRule (dst1Start), CreateFixedDateRule (dst1End));
+
+                               var rule2 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (
+                                       new DateTime (2014, 7, 1), new DateTime (2014, 12, 31), dstOffset,
+                                       CreateFixedDateRule (dst2Start), CreateFixedDateRule (dst2End));
+
+                               cairo = TimeZoneInfo.CreateCustomTimeZone ("Africa/Cairo", baseUtcOffset, "Africa/Cairo", "EET", "EEST",
+                                       new [] {rule1, rule2});
+                       }
+
+                       private static TimeZoneInfo.TransitionTime CreateFixedDateRule (DateTime dateTime)
+                       {
+                               var time = new DateTime (dateTime.Ticks - dateTime.Date.Ticks);
+                               return TimeZoneInfo.TransitionTime.CreateFixedDateRule (time, dateTime.Month, dateTime.Day);
+                       }
+
+                       [Test]
+                       public void GetUtcOffset_FromUTC ()
+                       {
+                               var d = dst1Start.Add (-baseUtcOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst1End.Add (-baseUtcOffset-dstOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst2Start.Add (-baseUtcOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst2End.Add (-baseUtcOffset-dstOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+                       }
+
+                       [Test]
+                       public void GetUtcOffset_FromLocal ()
+                       {
+                               var d = dst1Start.Add (-baseUtcOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               d = d.ToLocalTime ();
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst1End.Add (-baseUtcOffset-dstOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               d = d.ToLocalTime ();
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst2Start.Add (-baseUtcOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               d = d.ToLocalTime ();
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst2End.Add (-baseUtcOffset-dstOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               d = d.ToLocalTime ();
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+                       }
+
+                       [Test]
+                       public void GetUtcOffset_FromUnspecified ()
+                       {
+                               var d = dst1Start.Add (dstOffset);
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst1End.Add (-dstOffset);
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst2Start.Add (dstOffset);
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst2End.Add (-dstOffset);
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+                       }
+               }
        }
 }
 #endif
diff --git a/mcs/class/corlib/DateTime.Now_Test.sh b/mcs/class/corlib/DateTime.Now_Test.sh
new file mode 100755 (executable)
index 0000000..27b9c20
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+SCRIPT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+export MONO_PATH=${MONO_PATH:-$SCRIPT_PATH/../lib/net_4_5/}
+
+TZ_FAILS=0
+TZ_COUNT=0
+FORMAT="%a %b %d %T %Y"
+
+for tz in $(cd /usr/share/zoneinfo/; find * -type f -print); do
+       TZ_COUNT=$(expr $TZ_COUNT + 1)
+       SYS_DATETIME=$(date -ju -f "$FORMAT" "$(TZ=$tz date "+$FORMAT")" "+%s")
+       CS_DATETIME=$(TZ=$tz csharp -e '(int)(DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds;')
+       DIFF=$(expr $SYS_DATETIME - $CS_DATETIME)
+       if [ "$DIFF" -gt "5" ] || [ "$DIFF" -lt "-5" ]; then
+               TZ_FAILS=$(expr $TZ_FAILS + 1)
+               echo ""
+               echo "DateTime.Now failed with timezone: $tz"
+               echo "    System:       $(date -ju -f "%s" "$SYS_DATETIME" "+%Y-%m-%d %T")"
+               echo "    DateTime.Now: $(date -ju -f "%s" "$CS_DATETIME" "+%Y-%m-%d %T")"
+       fi
+       echo ".\c"
+done
+echo ""
+echo "DateTime.Now failed with $TZ_FAILS of $TZ_COUNT timezones."
index 7096e56cd33f94d6d47e167ec960162873defe24..7beb2d4982c93f211fe8de1d6fc1f6d0abd26d5c 100644 (file)
@@ -24,8 +24,6 @@
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#if NET_4_0
-
 using System.Runtime.CompilerServices;
 
 namespace System
@@ -36,7 +34,10 @@ namespace System
 #elif NET_4_0
        [TypeForwardedFrom (Consts.AssemblySystemCore_3_5)]
 #endif
-       public class InvalidTimeZoneException : Exception
+#if NET_4_0
+       public
+#endif
+       class InvalidTimeZoneException : Exception
        {
                public InvalidTimeZoneException () : base ()
                {}
@@ -51,5 +52,3 @@ namespace System
                {}
        }
 }
-
-#endif
index cea224133e4ab73ff1dbd3560b1f764d942c57aa..f4e01b03be322cc4f832f672002573eb025517f7 100644 (file)
@@ -144,22 +144,7 @@ namespace System
                                        return DateTime.SpecifyKind (DateTime.MinValue, DateTimeKind.Local);
                        }
 
-                       DateTime local = DateTime.SpecifyKind (time.Add (utcOffset), DateTimeKind.Local);
-                       DaylightTime dlt = GetDaylightChanges (time.Year);
-                       if (dlt.Delta.Ticks == 0)
-                               return DateTime.SpecifyKind (local, DateTimeKind.Local);
-
-                       // FIXME: check all of the combination of
-                       //      - basis: local-based or UTC-based
-                       //      - hemisphere: Northern or Southern
-                       //      - offset: positive or negative
-
-                       // PST should work fine here.
-                       if (local < dlt.End && dlt.End.Subtract (dlt.Delta) <= local)
-                               return DateTime.SpecifyKind (local, DateTimeKind.Local);
-
-                       TimeSpan localOffset = GetUtcOffset (local);
-                       return DateTime.SpecifyKind (time.Add (localOffset), DateTimeKind.Local);
+                       return DateTime.SpecifyKind (time.Add (utcOffset), DateTimeKind.Local);
                }
 
                public virtual DateTime ToUniversalTime (DateTime time)
@@ -252,17 +237,6 @@ namespace System
                // A yearwise cache of DaylightTime.
                private Dictionary<int, DaylightTime> m_CachedDaylightChanges = new Dictionary<int, DaylightTime> (1);
 
-               // the offset when daylightsaving is not on (in ticks)
-               private long m_ticksOffset;
-
-               // the offset when daylightsaving is not on.
-               [NonSerialized]
-               private TimeSpan utcOffsetWithOutDLS;
-  
-               // the offset when daylightsaving is on.
-               [NonSerialized]
-               private TimeSpan utcOffsetWithDLS;
-
                internal enum TimeZoneData
                {
                        DaylightSavingStartIdx,
@@ -315,8 +289,6 @@ namespace System
                        m_standardName = Locale.GetText (names[(int)TimeZoneNames.StandardNameIdx]);
                        m_daylightName = Locale.GetText (names[(int)TimeZoneNames.DaylightNameIdx]);
 
-                       m_ticksOffset = data[(int)TimeZoneData.UtcOffsetIdx];
-
                        DaylightTime dlt = GetDaylightTimeFromData (data);
                        m_CachedDaylightChanges.Add (now.Year, dlt);
                        OnDeserialization (dlt);
@@ -366,20 +338,7 @@ namespace System
                        if (time.Kind == DateTimeKind.Utc)
                                return TimeSpan.Zero;
 
-                       if (IsDaylightSavingTime (time) && !IsAmbiguousTime (time))
-                               return utcOffsetWithDLS;
-
-                       return utcOffsetWithOutDLS;
-               }
-
-               private bool IsAmbiguousTime (DateTime time)
-               {
-                       if (time.Kind == DateTimeKind.Utc)
-                               return false;
-
-                       DaylightTime changes = GetDaylightChanges (time.Year);
-
-                       return time < changes.End && time >= changes.End - changes.Delta;
+                       return TimeZoneInfo.Local.GetUtcOffset (time);
                }
 
                void IDeserializationCallback.OnDeserialization (object sender)
@@ -400,8 +359,6 @@ namespace System
                        } else
                                this_year = dlt.Start.Year;
                        
-                       utcOffsetWithOutDLS = new TimeSpan (m_ticksOffset);
-                       utcOffsetWithDLS = new TimeSpan (m_ticksOffset + dlt.Delta.Ticks);
                        this_year_dlt = dlt;
                }
 
index 79b094ddde0ad00192c63c5c9253dbfedb54cdec..643b82104b385eddeefe74e3532e6a9ff55b521c 100644 (file)
@@ -24,7 +24,6 @@
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#if NET_4_0
 
 using System.Runtime.CompilerServices;
 
@@ -36,7 +35,10 @@ namespace System
 #elif NET_4_0
        [TypeForwardedFrom (Consts.AssemblySystemCore_3_5)]
 #endif
-       public class TimeZoneNotFoundException : Exception
+#if NET_4_0
+       public
+#endif
+       class TimeZoneNotFoundException : Exception
        {
                public TimeZoneNotFoundException () : base ()
                {}
@@ -51,5 +53,3 @@ namespace System
                {}
        }
 }
-
-#endif