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
36 changes: 36 additions & 0 deletions Ical.Net.Tests/VTimeZoneTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,42 @@ public void VTimeZoneEuropeMoscowShouldSerializeProperly()
}
}

[TestCase("Australia/Sydney", "+1000", "+1100", "T020000")]
[TestCase("Australia/Lord_Howe", "+1030", "+1100", "T020000")]
[TestCase("Australia/Adelaide", "+0930", "+1030", "T020000")]
[TestCase("Australia/Broken_Hill", "+0930", "+1030", "T020000")]
[TestCase("Pacific/Auckland", "+1200", "+1300", "T020000")]
[TestCase("Pacific/Easter", "-0600", "-0500", "T220000")]
[TestCase("Pacific/Chatham", "+1245", "+1345", "T024500")]
[TestCase("America/Santiago", "-0400", "-0300", "T000000")]
[TestCase("Antarctica/Macquarie", "+1000", "+1100", "T020000")]
[Category("VTimeZone")]
public void VTimeZoneSouthernHemisphereDetermineDaylight(string tzId, string expectedOffsetFrom,
string expectedOffsetTo, string expectedDtStartTime)
{
TimeZoneInfo tzInfo;
try
{
tzInfo = TimeZoneInfo.FindSystemTimeZoneById(tzId);
}
catch (TimeZoneNotFoundException)
{
Assert.Ignore($"Time zone '{tzId}' was not found on the local machine.");
return;
}

var tz = VTimeZone.FromSystemTimeZone(tzInfo, new DateTime(2024, 1, 1), false);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use VTimeZone.FromDateTimeZone(tzId, ...) directly. Both methods just use the TZID to get the NodaTime time zone anyway.

var daylight = tz.TimeZoneInfos.FirstOrDefault(x => x.Name == "DAYLIGHT")!;

Comment thread
axunonb marked this conversation as resolved.
Resolved
using (Assert.EnterMultipleScope())
{
Assert.That(daylight, Is.Not.Null);
Assert.That(daylight.OffsetFrom?.ToString(), Is.EqualTo(expectedOffsetFrom));
Assert.That(daylight.OffsetTo?.ToString(), Is.EqualTo(expectedOffsetTo));
Assert.That(daylight.DtStart!.ToBasicIso(), Does.EndWith(expectedDtStartTime));
}
}

[Test, Category("VTimeZone")]
public void VTimeZoneAmericaChicagoShouldSerializeProperly()
{
Expand Down
19 changes: 13 additions & 6 deletions Ical.Net/CalendarComponents/VTimeZone.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ internal static VTimeZone FromDateTimeZone(
wallOffset: tz.MinOffset,
savings: Offset.Zero);
intervals.Add(interval);
var zoneInfo = CreateTimeZoneInfo(intervals, [], true, true);
var zoneInfo = CreateTimeZoneInfo(tz, intervals, [], true, true);
vTimeZone.AddChild(zoneInfo);
}
else
Expand All @@ -114,7 +114,7 @@ internal static VTimeZone FromDateTimeZone(
}

matchingStandardIntervals = GetMatchingIntervals(standardIntervals, latestStandardInterval, true);
var latestStandardTimeZoneInfo = CreateTimeZoneInfo(matchingStandardIntervals, intervals);
var latestStandardTimeZoneInfo = CreateTimeZoneInfo(tz, matchingStandardIntervals, intervals);
vTimeZone.AddChild(latestStandardTimeZoneInfo);

// check to see if there is no active, future daylight savings (ie, America/Phoenix)
Expand All @@ -128,7 +128,7 @@ internal static VTimeZone FromDateTimeZone(
var latestDaylightInterval = daylightIntervals.OrderByDescending(x => x.Start).First();
matchingDaylightIntervals =
GetMatchingIntervals(daylightIntervals, latestDaylightInterval, true);
var latestDaylightTimeZoneInfo = CreateTimeZoneInfo(matchingDaylightIntervals, intervals);
var latestDaylightTimeZoneInfo = CreateTimeZoneInfo(tz, matchingDaylightIntervals, intervals);
vTimeZone.AddChild(latestDaylightTimeZoneInfo);
}
}
Expand All @@ -152,15 +152,15 @@ internal static VTimeZone FromDateTimeZone(
}

var matchedIntervals = GetMatchingIntervals(historicIntervals, interval);
var timeZoneInfo = CreateTimeZoneInfo(matchedIntervals, intervals, false);
var timeZoneInfo = CreateTimeZoneInfo(tz, matchedIntervals, intervals, false);
vTimeZone.AddChild(timeZoneInfo);
historicIntervals = historicIntervals.Where(x => !matchedIntervals.Contains(x)).ToList();
}

return vTimeZone;
}

private static VTimeZoneInfo CreateTimeZoneInfo(List<ZoneInterval> matchedIntervals, List<ZoneInterval> intervals, bool isRRule = true,
private static VTimeZoneInfo CreateTimeZoneInfo(DateTimeZone tz, List<ZoneInterval> matchedIntervals, List<ZoneInterval> intervals, bool isRRule = true,
bool isOnlyInterval = false)
{
if (matchedIntervals == null || matchedIntervals.Count == 0)
Expand All @@ -176,7 +176,7 @@ private static VTimeZoneInfo CreateTimeZoneInfo(List<ZoneInterval> matchedInterv

var previousInterval = intervals.SingleOrDefault(x => (x.HasEnd ? x.End : Instant.MaxValue) == oldestInterval.Start);

var delta = new TimeSpan(1, 0, 0);
TimeSpan delta;

if (previousInterval != null)
{
Expand All @@ -186,6 +186,13 @@ private static VTimeZoneInfo CreateTimeZoneInfo(List<ZoneInterval> matchedInterv
{
delta = TimeSpan.Zero;
}
else
{
// The true predecessor was not collected in the interval range (e.g. southern-hemisphere
// zones where Jan 1st falls inside DST). Look it up directly from the time zone itself.
var actualPrevious = tz.GetZoneInterval(oldestInterval.Start - NodaTime.Duration.Epsilon);
delta = new TimeSpan(0, 0, actualPrevious.WallOffset.Seconds - oldestInterval.WallOffset.Seconds);
}

var utcOffset = oldestInterval.StandardOffset.ToTimeSpan();

Expand Down
Loading