Skip to content

Commit 803219e

Browse files
authored
Resolved issues where schedules crossed daylight savings boundaries (#139)
Resolved issue where a schedule was not correctly calculated if the daylight saving offset occurred on the next iteration of the schedule. Resolved issue with .FirstOrDefault which was returning DateTime.MinValue if no schedule was found.
1 parent 5b3d33a commit 803219e

4 files changed

Lines changed: 31 additions & 8 deletions

File tree

MFiles.VAF.Extensions.Tests/Configuration/ScheduledExecution/WeeklyTriggerTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,5 +193,23 @@ public static IEnumerable<object[]> GetNextDayOfWeekData()
193193
new DateTime ?[] { new DateTime(2021, 03, 20, 0, 0, 0, 0) }
194194
};
195195
}
196+
197+
[TestMethod]
198+
public void WeeklyValueNotReturnedWhenDaylightsavingChanges()
199+
{
200+
var now = new DateTimeOffset(new DateTime(2024, 10, 23, 10, 27, 0), new TimeSpan(0, 0, 0));
201+
var expected = new DateTimeOffset(new DateTime(2024, 10, 30, 9, 0, 0), new TimeSpan(2, 0, 0));
202+
203+
var trigger = new WeeklyTrigger()
204+
{
205+
TriggerTimes = new List<TimeSpan>()
206+
{
207+
new TimeSpan(9, 0, 0)
208+
},
209+
TriggerDays = new List<DayOfWeek>() { DayOfWeek.Wednesday }
210+
};
211+
var execution = trigger.GetNextExecution(now, TimeZoneInfo.FindSystemTimeZoneById("FLE Standard Time"));
212+
Assert.AreEqual(expected.ToUniversalTime(), execution?.ToUniversalTime());
213+
}
196214
}
197215
}

MFiles.VAF.Extensions/Configuration/ScheduledExecution/DailyTrigger.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public DailyTrigger()
5959
timeZoneInfo = timeZoneInfo ?? TimeZoneInfo.Local;
6060

6161
// When should we start looking?
62+
var before = after.Value;
6263
after = (after ?? DateTime.UtcNow).ToUniversalTime();
6364

6465
// Convert the time into the timezone we're after.
@@ -73,7 +74,12 @@ public DailyTrigger()
7374
// What is the potential time that this will run?
7475
DateTimeOffset potential;
7576
{
76-
var dateTime = after.Value.Date.Add(t);
77+
// If the timezone conversion changed the date then go back to the start of the date.
78+
var date = after.Value.Date;
79+
if (after.Value.Date != before.Date)
80+
date = new DateTime(before.Date.Ticks);
81+
82+
var dateTime = date.Add(t);
7783
potential = new DateTimeOffset(dateTime, timeZoneInfo.GetUtcOffset(dateTime));
7884
}
7985

MFiles.VAF.Extensions/Configuration/ScheduledExecution/Schedule.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,11 @@ public class Schedule
106106
}
107107

108108
// Get the next execution date from the triggers.
109-
return this.Triggers?
109+
var next = this.Triggers?
110110
.Select(t => t.GetNextExecution(after, timeZoneInfo))
111-
.Where(d => d.HasValue)
112-
.OrderBy(d => d)
113-
.FirstOrDefault();
111+
.Where(d => d.HasValue && d.Value.DateTime != DateTime.MinValue)
112+
.OrderBy(d => d);
113+
return next.Any() ? next.First() : null;
114114
}
115115

116116

MFiles.VAF.Extensions/Configuration/ScheduledExecution/WeeklyTrigger.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,12 @@ public WeeklyTrigger()
7474
.Select(d => d.Value)
7575
.Where(d => d > after.Value)
7676
.OrderBy(d => d)
77+
.Select(d => d.ToUniversalTime())
7778
.ToList();
7879

7980
this.Logger?.Trace($"These are the potential matches: {string.Join(", ", potentialMatches)}");
8081

81-
return potentialMatches
82-
.Select(d => d.ToUniversalTime())
83-
.FirstOrDefault();
82+
return potentialMatches.Any() ? (DateTimeOffset?)potentialMatches.First() : null;
8483
}
8584

8685
/// <summary>

0 commit comments

Comments
 (0)