From 843fd903840501d0082300b7f7755f55e38ae450 Mon Sep 17 00:00:00 2001 From: Craig Hawker Date: Wed, 23 Oct 2024 11:42:34 +0100 Subject: [PATCH] Resolved issue with .FirstOrDefault which was returning DateTime.MinValue if no schedule was found. Resolved issue where a schedule was not correctly calculated if the daylight saving offset occurred on the next iteration of the schedule. --- .../ScheduledExecution/WeeklyTriggerTests.cs | 18 ++++++++++++++++++ .../ScheduledExecution/DailyTrigger.cs | 8 +++++++- .../ScheduledExecution/Schedule.cs | 8 ++++---- .../ScheduledExecution/WeeklyTrigger.cs | 5 ++--- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/MFiles.VAF.Extensions.Tests/Configuration/ScheduledExecution/WeeklyTriggerTests.cs b/MFiles.VAF.Extensions.Tests/Configuration/ScheduledExecution/WeeklyTriggerTests.cs index 362eb9dd..9f9b04ce 100644 --- a/MFiles.VAF.Extensions.Tests/Configuration/ScheduledExecution/WeeklyTriggerTests.cs +++ b/MFiles.VAF.Extensions.Tests/Configuration/ScheduledExecution/WeeklyTriggerTests.cs @@ -193,5 +193,23 @@ public static IEnumerable GetNextDayOfWeekData() new DateTime ?[] { new DateTime(2021, 03, 20, 0, 0, 0, 0) } }; } + + [TestMethod] + public void WeeklyValueNotReturnedWhenDaylightsavingChanges() + { + var now = new DateTimeOffset(new DateTime(2024, 10, 23, 10, 27, 0), new TimeSpan(0, 0, 0)); + var expected = new DateTimeOffset(new DateTime(2024, 10, 30, 9, 0, 0), new TimeSpan(2, 0, 0)); + + var trigger = new WeeklyTrigger() + { + TriggerTimes = new List() + { + new TimeSpan(9, 0, 0) + }, + TriggerDays = new List() { DayOfWeek.Wednesday } + }; + var execution = trigger.GetNextExecution(now, TimeZoneInfo.FindSystemTimeZoneById("FLE Standard Time")); + Assert.AreEqual(expected.ToUniversalTime(), execution?.ToUniversalTime()); + } } } diff --git a/MFiles.VAF.Extensions/Configuration/ScheduledExecution/DailyTrigger.cs b/MFiles.VAF.Extensions/Configuration/ScheduledExecution/DailyTrigger.cs index c4abc532..3110a93e 100644 --- a/MFiles.VAF.Extensions/Configuration/ScheduledExecution/DailyTrigger.cs +++ b/MFiles.VAF.Extensions/Configuration/ScheduledExecution/DailyTrigger.cs @@ -59,6 +59,7 @@ public DailyTrigger() timeZoneInfo = timeZoneInfo ?? TimeZoneInfo.Local; // When should we start looking? + var before = after.Value; after = (after ?? DateTime.UtcNow).ToUniversalTime(); // Convert the time into the timezone we're after. @@ -73,7 +74,12 @@ public DailyTrigger() // What is the potential time that this will run? DateTimeOffset potential; { - var dateTime = after.Value.Date.Add(t); + // If the timezone conversion changed the date then go back to the start of the date. + var date = after.Value.Date; + if (after.Value.Date != before.Date) + date = new DateTime(before.Date.Ticks); + + var dateTime = date.Add(t); potential = new DateTimeOffset(dateTime, timeZoneInfo.GetUtcOffset(dateTime)); } diff --git a/MFiles.VAF.Extensions/Configuration/ScheduledExecution/Schedule.cs b/MFiles.VAF.Extensions/Configuration/ScheduledExecution/Schedule.cs index 1c2e6e41..906312f7 100644 --- a/MFiles.VAF.Extensions/Configuration/ScheduledExecution/Schedule.cs +++ b/MFiles.VAF.Extensions/Configuration/ScheduledExecution/Schedule.cs @@ -106,11 +106,11 @@ public class Schedule } // Get the next execution date from the triggers. - return this.Triggers? + var next = this.Triggers? .Select(t => t.GetNextExecution(after, timeZoneInfo)) - .Where(d => d.HasValue) - .OrderBy(d => d) - .FirstOrDefault(); + .Where(d => d.HasValue && d.Value.DateTime != DateTime.MinValue) + .OrderBy(d => d); + return next.Any() ? next.First() : null; } diff --git a/MFiles.VAF.Extensions/Configuration/ScheduledExecution/WeeklyTrigger.cs b/MFiles.VAF.Extensions/Configuration/ScheduledExecution/WeeklyTrigger.cs index e35ce7f0..17ed8f3e 100644 --- a/MFiles.VAF.Extensions/Configuration/ScheduledExecution/WeeklyTrigger.cs +++ b/MFiles.VAF.Extensions/Configuration/ScheduledExecution/WeeklyTrigger.cs @@ -74,13 +74,12 @@ public WeeklyTrigger() .Select(d => d.Value) .Where(d => d > after.Value) .OrderBy(d => d) + .Select(d => d.ToUniversalTime()) .ToList(); this.Logger?.Trace($"These are the potential matches: {string.Join(", ", potentialMatches)}"); - return potentialMatches - .Select(d => d.ToUniversalTime()) - .FirstOrDefault(); + return potentialMatches.Any() ? (DateTimeOffset?)potentialMatches.First() : null; } ///