提交 5a853002 编写于 作者: M Maxim Lipnin 提交者: Scott Ferguson

Port 13553 "Fix transition offset logic" to master

上级 ad6f94d8
...@@ -805,7 +805,7 @@ namespace System ...@@ -805,7 +805,7 @@ namespace System
return GetUtcOffset (dateTimeOffset.UtcDateTime, out isDST); return GetUtcOffset (dateTimeOffset.UtcDateTime, out isDST);
} }
private TimeSpan GetUtcOffset (DateTime dateTime, out bool isDST) private TimeSpan GetUtcOffset (DateTime dateTime, out bool isDST, bool forOffset = false)
{ {
isDST = false; isDST = false;
...@@ -817,7 +817,7 @@ namespace System ...@@ -817,7 +817,7 @@ namespace System
tz = TimeZoneInfo.Local; tz = TimeZoneInfo.Local;
bool isTzDst; bool isTzDst;
var tzOffset = GetUtcOffsetHelper (dateTime, tz, out isTzDst); var tzOffset = GetUtcOffsetHelper (dateTime, tz, out isTzDst, forOffset);
if (tz == this) { if (tz == this) {
isDST = isTzDst; isDST = isTzDst;
...@@ -828,11 +828,11 @@ namespace System ...@@ -828,11 +828,11 @@ namespace System
if (!TryAddTicks (dateTime, -tzOffset.Ticks, out utcDateTime, DateTimeKind.Utc)) if (!TryAddTicks (dateTime, -tzOffset.Ticks, out utcDateTime, DateTimeKind.Utc))
return BaseUtcOffset; return BaseUtcOffset;
return GetUtcOffsetHelper (utcDateTime, this, out isDST); return GetUtcOffsetHelper (utcDateTime, this, out isDST, forOffset);
} }
// This is an helper method used by the method above, do not use this on its own. // This is an helper method used by the method above, do not use this on its own.
private static TimeSpan GetUtcOffsetHelper (DateTime dateTime, TimeZoneInfo tz, out bool isDST) private static TimeSpan GetUtcOffsetHelper (DateTime dateTime, TimeZoneInfo tz, out bool isDST, bool forOffset = false)
{ {
if (dateTime.Kind == DateTimeKind.Local && tz != TimeZoneInfo.Local) if (dateTime.Kind == DateTimeKind.Local && tz != TimeZoneInfo.Local)
throw new Exception (); throw new Exception ();
...@@ -843,7 +843,7 @@ namespace System ...@@ -843,7 +843,7 @@ namespace System
return TimeSpan.Zero; return TimeSpan.Zero;
TimeSpan offset; TimeSpan offset;
if (tz.TryGetTransitionOffset(dateTime, out offset, out isDST)) if (tz.TryGetTransitionOffset(dateTime, out offset, out isDST, forOffset))
return offset; return offset;
if (dateTime.Kind == DateTimeKind.Utc) { if (dateTime.Kind == DateTimeKind.Utc) {
...@@ -870,10 +870,12 @@ namespace System ...@@ -870,10 +870,12 @@ namespace System
if (tzRule != null && tz.IsInDST (tzRule, dateTime)) { if (tzRule != null && tz.IsInDST (tzRule, dateTime)) {
// Replicate what .NET does when given a time which falls into the hour which is lost when // Replicate what .NET does when given a time which falls into the hour which is lost when
// DST starts. isDST should always be true but the offset should be BaseUtcOffset without the // DST starts. isDST should be false and the offset should be BaseUtcOffset without the
// DST delta while in that hour. // DST delta while in that hour.
isDST = true; if (forOffset)
isDST = true;
if (tz.IsInDST (tzRule, dstUtcDateTime)) { if (tz.IsInDST (tzRule, dstUtcDateTime)) {
isDST = true;
return tz.BaseUtcOffset + tzRule.DaylightDelta; return tz.BaseUtcOffset + tzRule.DaylightDelta;
} else { } else {
return tz.BaseUtcOffset; return tz.BaseUtcOffset;
...@@ -982,7 +984,21 @@ namespace System ...@@ -982,7 +984,21 @@ namespace System
public bool IsDaylightSavingTime (DateTimeOffset dateTimeOffset) public bool IsDaylightSavingTime (DateTimeOffset dateTimeOffset)
{ {
return IsDaylightSavingTime (dateTimeOffset.DateTime); var dateTime = dateTimeOffset.DateTime;
if (dateTime.Kind == DateTimeKind.Local && IsInvalidTime (dateTime))
throw new ArgumentException ("dateTime is invalid and Kind is Local");
if (this == TimeZoneInfo.Utc)
return false;
if (!SupportsDaylightSavingTime)
return false;
bool isDst;
GetUtcOffset (dateTime, out isDst, true);
return isDst;
} }
internal DaylightTime GetDaylightChanges (int year) internal DaylightTime GetDaylightChanges (int year)
...@@ -1219,7 +1235,7 @@ namespace System ...@@ -1219,7 +1235,7 @@ namespace System
return null; return null;
} }
private bool TryGetTransitionOffset (DateTime dateTime, out TimeSpan offset,out bool isDst) private bool TryGetTransitionOffset (DateTime dateTime, out TimeSpan offset, out bool isDst, bool forOffset = false)
{ {
offset = BaseUtcOffset; offset = BaseUtcOffset;
isDst = false; isDst = false;
...@@ -1240,13 +1256,22 @@ namespace System ...@@ -1240,13 +1256,22 @@ namespace System
return false; return false;
} }
AdjustmentRule current = GetApplicableRule(date); AdjustmentRule current = GetApplicableRule (date);
if (current != null) { if (current != null) {
DateTime tStart = TransitionPoint(current.DaylightTransitionStart, date.Year); DateTime tStart = TransitionPoint (current.DaylightTransitionStart, date.Year);
DateTime tEnd = TransitionPoint(current.DaylightTransitionEnd, date.Year); DateTime tEnd = TransitionPoint (current.DaylightTransitionEnd, date.Year);
TryAddTicks (tStart, -BaseUtcOffset.Ticks, out tStart, DateTimeKind.Utc);
TryAddTicks (tEnd, -BaseUtcOffset.Ticks, out tEnd, DateTimeKind.Utc);
if ((date >= tStart) && (date <= tEnd)) { if ((date >= tStart) && (date <= tEnd)) {
offset = baseUtcOffset + current.DaylightDelta; if (forOffset)
isDst = true; isDst = true;
offset = baseUtcOffset;
if (date >= new DateTime (tStart.Ticks + current.DaylightDelta.Ticks, DateTimeKind.Utc))
{
offset += current.DaylightDelta;
isDst = true;
}
return true; return true;
} }
} }
......
...@@ -55,6 +55,8 @@ namespace MonoTests.System ...@@ -55,6 +55,8 @@ namespace MonoTests.System
return "GTB Standard Time"; return "GTB Standard Time";
case "US/Eastern": case "US/Eastern":
return "Eastern Standard Time"; return "Eastern Standard Time";
case "US/Central":
return "Central Standard Time";
case "US/Pacific": case "US/Pacific":
return "Pacific Standard Time"; return "Pacific Standard Time";
case "Australia/Sydney": case "Australia/Sydney":
...@@ -760,13 +762,18 @@ namespace MonoTests.System ...@@ -760,13 +762,18 @@ namespace MonoTests.System
[Test] [Test]
public void TestAthensDST_InDSTDelta () public void TestAthensDST_InDSTDelta ()
{ {
// In .NET GetUtcOffset() returns the BaseUtcOffset for times within the hour // In .NET/.Net Core GetUtcOffset() returns the BaseUtcOffset for times within the hour
// lost when DST starts but IsDaylightSavingTime() returns true. // lost when DST starts and IsDaylightSavingTime() returns false for datetime and true for datetimeoffset
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById (MapTimeZoneId ("Europe/Athens")); TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById (MapTimeZoneId ("Europe/Athens"));
var date = new DateTime (2014, 3, 30 , 3, 0, 0); var date = new DateTime (2014, 3, 30 , 2, 0, 0);
Assert.IsTrue (tzi.IsDaylightSavingTime (date)); Assert.IsFalse (tzi.IsDaylightSavingTime (date));
Assert.AreEqual (new TimeSpan (2, 0, 0), tzi.GetUtcOffset (date));
Assert.IsFalse (tzi.IsDaylightSavingTime (new DateTimeOffset (date, tzi.GetUtcOffset (date))));
date = new DateTime (2014, 3, 30 , 3, 0, 0);
Assert.IsFalse (tzi.IsDaylightSavingTime (date));
Assert.AreEqual (new TimeSpan (2, 0, 0), tzi.GetUtcOffset (date)); Assert.AreEqual (new TimeSpan (2, 0, 0), tzi.GetUtcOffset (date));
Assert.IsTrue (tzi.IsDaylightSavingTime (new DateTimeOffset (date, tzi.GetUtcOffset (date)))); Assert.IsTrue (tzi.IsDaylightSavingTime (new DateTimeOffset (date, tzi.GetUtcOffset (date))));
...@@ -842,6 +849,31 @@ namespace MonoTests.System ...@@ -842,6 +849,31 @@ namespace MonoTests.System
dateOffset = new DateTimeOffset (date, offset); dateOffset = new DateTimeOffset (date, offset);
Assert.IsTrue (tzi.IsDaylightSavingTime (dateOffset)); Assert.IsTrue (tzi.IsDaylightSavingTime (dateOffset));
} }
// https://github.com/mono/mono/issues/9664
[Test]
public void Bug_9664 ()
{
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById (MapTimeZoneId ("US/Central"));
var date = new DateTime (2019, 3, 9, 21, 0, 0);
Assert.IsFalse (tzi.IsDaylightSavingTime (date));
Assert.AreEqual (new TimeSpan (-6, 0, 0), tzi.GetUtcOffset (date));
tzi = TimeZoneInfo.FindSystemTimeZoneById (MapTimeZoneId ("US/Central"));
date = new DateTime (2019, 3, 10, 2, 0, 0);
Assert.IsFalse (tzi.IsDaylightSavingTime (date));
Assert.AreEqual (new TimeSpan (-6, 0, 0), tzi.GetUtcOffset (date));
tzi = TimeZoneInfo.FindSystemTimeZoneById (MapTimeZoneId ("US/Central"));
date = new DateTime (2019, 3, 10, 2, 30, 0);
Assert.IsFalse (tzi.IsDaylightSavingTime (date));
Assert.AreEqual (new TimeSpan (-6, 0, 0), tzi.GetUtcOffset (date));
tzi = TimeZoneInfo.FindSystemTimeZoneById (MapTimeZoneId ("US/Central"));
date = new DateTime (2019, 3, 10, 3, 0, 0);
Assert.IsTrue (tzi.IsDaylightSavingTime (date));
Assert.AreEqual (new TimeSpan (-5, 0, 0), tzi.GetUtcOffset (date));
}
} }
[TestFixture] [TestFixture]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册