CurrentSystemTimeZone.GetUtcOffset now supports multiple DST periods.
* 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)]
* 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;
namespace System
{
- public partial class TimeZoneInfo
+#if NET_4_0 || !INSIDE_CORLIB
+ public
+#endif
+ partial class TimeZoneInfo
{
public static TimeZoneInfo FromSerializedString (string source)
{
* 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
[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;
[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 {
}
}
+ /*
+ TimeZone transitions are stored when there is a change on the base offset.
+ */
+ private List<KeyValuePair<DateTime, TimeType>> transitions;
+
static TimeZoneInfo CreateLocal ()
{
#if MONODROID
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 {
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)
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 {
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)
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)
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);
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)
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)
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];
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;
}
}
}
- 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)
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");
}
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
--- /dev/null
+#!/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."
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#if NET_4_0
-
using System.Runtime.CompilerServices;
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 ()
{}
{}
}
}
-
-#endif
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)
// 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,
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);
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)
} else
this_year = dlt.Start.Year;
- utcOffsetWithOutDLS = new TimeSpan (m_ticksOffset);
- utcOffsetWithDLS = new TimeSpan (m_ticksOffset + dlt.Delta.Ticks);
this_year_dlt = dlt;
}
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#if NET_4_0
using System.Runtime.CompilerServices;
#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 ()
{}
{}
}
}
-
-#endif