Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 106 additions & 22 deletions mcs/class/corlib/System/TimeZoneInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ public TimeSpan GetUtcOffset (DateTimeOffset dateTimeOffset)
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;

Expand All @@ -817,7 +817,7 @@ private TimeSpan GetUtcOffset (DateTime dateTime, out bool isDST)
tz = TimeZoneInfo.Local;

bool isTzDst;
var tzOffset = GetUtcOffsetHelper (dateTime, tz, out isTzDst);
var tzOffset = GetUtcOffsetHelper (dateTime, tz, out isTzDst, forOffset);

if (tz == this) {
isDST = isTzDst;
Expand All @@ -828,11 +828,11 @@ private TimeSpan GetUtcOffset (DateTime dateTime, out bool isDST)
if (!TryAddTicks (dateTime, -tzOffset.Ticks, out utcDateTime, DateTimeKind.Utc))
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.
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)
throw new Exception ();
Expand All @@ -843,7 +843,7 @@ private static TimeSpan GetUtcOffsetHelper (DateTime dateTime, TimeZoneInfo tz,
return TimeSpan.Zero;

TimeSpan offset;
if (tz.TryGetTransitionOffset(dateTime, out offset, out isDST))
if (tz.TryGetTransitionOffset(dateTime, out offset, out isDST, forOffset))
return offset;

if (dateTime.Kind == DateTimeKind.Utc) {
Expand All @@ -870,10 +870,12 @@ private static TimeSpan GetUtcOffsetHelper (DateTime dateTime, TimeZoneInfo tz,

if (tzRule != null && tz.IsInDST (tzRule, dateTime)) {
// 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.
isDST = true;
if (forOffset)
isDST = true;
if (tz.IsInDST (tzRule, dstUtcDateTime)) {
isDST = true;
return tz.BaseUtcOffset + tzRule.DaylightDelta;
} else {
return tz.BaseUtcOffset;
Expand Down Expand Up @@ -925,7 +927,33 @@ public bool IsAmbiguousTime (DateTime dateTime)
AdjustmentRule rule = GetApplicableRule (dateTime);
if (rule != null) {
DateTime tpoint = TransitionPoint (rule.DaylightTransitionEnd, dateTime.Year);
if (dateTime > tpoint - rule.DaylightDelta && dateTime <= tpoint)
if (dateTime >= tpoint - rule.DaylightDelta && dateTime < tpoint)
return true;
}

return false;
}

private bool IsAmbiguousLocalDstFromUtc (DateTime dateTime)
{
// This method determines if a dateTime in UTC falls into the Dst side
// of the ambiguous local time (the local time that occurs twice).

if (dateTime.Kind == DateTimeKind.Local)
return false;

if (this == TimeZoneInfo.Utc)
return false;

AdjustmentRule rule = GetApplicableRule (dateTime);
if (rule != null) {
DateTime tpoint = TransitionPoint (rule.DaylightTransitionEnd, dateTime.Year);
// tpoint is the local time in daylight savings time when daylight savings time will end, convert it to UTC
DateTime tpointUtc;
if (!TryAddTicks(tpoint, -(BaseUtcOffset.Ticks + rule.DaylightDelta.Ticks), out tpointUtc, DateTimeKind.Utc))
return false;

if (dateTime >= tpointUtc - rule.DaylightDelta && dateTime < tpointUtc)
return true;
}

Expand All @@ -944,7 +972,18 @@ private bool IsInDST (AdjustmentRule rule, DateTime dateTime)
return true;

// We might be in the dateTime previous year's DST period
return dateTime.Year > 1 && IsInDSTForYear (rule, dateTime, dateTime.Year - 1);
if (dateTime.Year > 1 && IsInDSTForYear(rule, dateTime, dateTime.Year - 1))
return true;

// If we are checking an ambiguous local time, that is the local time that occurs twice during a DST "fall back"
// check if it was marked as being in the DST side of the ambiguous time when it was created
// We need to re-check IsAmbiguousTime because the IsAmbiguousDaylightSavingTime flag is not cleared when using DateTime.Add/Subtract
if (dateTime.Kind == DateTimeKind.Local && IsAmbiguousTime(dateTime))
{
return dateTime.IsAmbiguousDaylightSavingTime();
}

return false;
}

bool IsInDSTForYear (AdjustmentRule rule, DateTime dateTime, int year)
Expand All @@ -953,8 +992,9 @@ bool IsInDSTForYear (AdjustmentRule rule, DateTime dateTime, int year)
DateTime DST_end = TransitionPoint (rule.DaylightTransitionEnd, year + ((rule.DaylightTransitionStart.Month < rule.DaylightTransitionEnd.Month) ? 0 : 1));
if (dateTime.Kind == DateTimeKind.Utc) {
DST_start -= BaseUtcOffset;
DST_end -= (BaseUtcOffset + rule.DaylightDelta);
DST_end -= BaseUtcOffset;
}
DST_end -= rule.DaylightDelta;
return (dateTime >= DST_start && dateTime < DST_end);
}

Expand Down Expand Up @@ -982,7 +1022,21 @@ internal bool IsDaylightSavingTime (DateTime dateTime, TimeZoneInfoOptions flags

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)
Expand Down Expand Up @@ -1219,7 +1273,7 @@ private AdjustmentRule GetApplicableRule (DateTime dateTime)
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;
isDst = false;
Expand All @@ -1235,18 +1289,45 @@ private bool TryGetTransitionOffset (DateTime dateTime, out TimeSpan offset,out
return false;
}

var isUtc = false;
if (dateTime.Kind != DateTimeKind.Utc) {
if (!TryAddTicks (date, -BaseUtcOffset.Ticks, out date, DateTimeKind.Utc))
return false;
}
} else
isUtc = true;


AdjustmentRule current = GetApplicableRule(date);
AdjustmentRule current = GetApplicableRule (date);
if (current != null) {
DateTime tStart = TransitionPoint(current.DaylightTransitionStart, date.Year);
DateTime tEnd = TransitionPoint(current.DaylightTransitionEnd, date.Year);
DateTime tStart = TransitionPoint (current.DaylightTransitionStart, 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)) {
offset = baseUtcOffset + current.DaylightDelta;
isDst = true;
if (forOffset)
isDst = true;
offset = baseUtcOffset;
if (isUtc || (date >= new DateTime (tStart.Ticks + current.DaylightDelta.Ticks, DateTimeKind.Utc)))
{
offset += current.DaylightDelta;
isDst = true;
}

if (date >= new DateTime (tEnd.Ticks - current.DaylightDelta.Ticks, DateTimeKind.Utc))
{
offset = baseUtcOffset;
isDst = false;
}

// If we are checking an ambiguous local time, that is the local time that occurs twice during a DST "fall back"
// check if it was marked as being in the DST side of the ambiguous time when it was created
// We need to re-check IsAmbiguousTime because the IsAmbiguousDaylightSavingTime flag is not cleared when using DateTime.Add/Subtract
if (!isDst && dateTime.Kind == DateTimeKind.Local && IsAmbiguousTime(dateTime) && dateTime.IsAmbiguousDaylightSavingTime())
{
offset += current.DaylightDelta;
isDst = true;
}

return true;
}
}
Expand All @@ -1255,8 +1336,11 @@ private bool TryGetTransitionOffset (DateTime dateTime, out TimeSpan offset,out

private static DateTime TransitionPoint (TransitionTime transition, int year)
{
if (transition.IsFixedDateRule)
return new DateTime (year, transition.Month, transition.Day) + transition.TimeOfDay.TimeOfDay;
if (transition.IsFixedDateRule) {
var daysInMonth = DateTime.DaysInMonth (year, transition.Month);
var transitionDay = transition.Day <= daysInMonth ? transition.Day : daysInMonth;
return new DateTime (year, transition.Month, transitionDay) + transition.TimeOfDay.TimeOfDay;
}

DayOfWeek first = (new DateTime (year, transition.Month, 1)).DayOfWeek;
int day = 1 + (transition.Week - 1) * 7 + (transition.DayOfWeek - first + 7) % 7;
Expand Down Expand Up @@ -1540,7 +1624,7 @@ static internal TimeSpan GetUtcOffsetFromUtc (DateTime time, TimeZoneInfo zone,
isAmbiguousLocalDst = false;
TimeSpan baseOffset = zone.BaseUtcOffset;

if (zone.IsAmbiguousTime (time)) {
if (zone.IsAmbiguousLocalDstFromUtc (time)) {
isAmbiguousLocalDst = true;
// return baseOffset;
}
Expand Down Expand Up @@ -1570,4 +1654,4 @@ public override string ToString ()
}
#endif
}
}
}
Loading