From e28dc48bd055bbb8594936e5ff2516f9a263e2d6 Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Mon, 26 Oct 2026 09:10:00 -0700 Subject: [PATCH] case 4682 - automatic backup runs at the chosen time on the server's clock all year Same fix as AyaNova: the backup ran at the stored UTC hour, so with daylight saving it moved an hour on the server's clock for part of the year. Co-Authored-By: Claude Opus 5.5 --- server/util/ServerGlobalOpsSettingsCache.cs | 22 +++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/server/util/ServerGlobalOpsSettingsCache.cs b/server/util/ServerGlobalOpsSettingsCache.cs index f553f0d..93fd099 100644 --- a/server/util/ServerGlobalOpsSettingsCache.cs +++ b/server/util/ServerGlobalOpsSettingsCache.cs @@ -51,22 +51,36 @@ namespace Sockeye.Util internal static void SetNextBackup() { DateTime utcNow = DateTime.UtcNow; + //case 4682: the backup time is a time on the server's clock; days are the server's local days + DateTime localToday = TimeZoneInfo.ConvertTimeFromUtc(utcNow, TimeZoneInfo.Local).Date; //Has last backup run more than 24 hours ago? if (NextBackup < utcNow.AddHours(-24)) { //set it to today then - NextBackup = new DateTime(utcNow.Year, utcNow.Month, utcNow.Day, Backup.BackupTime.Hour, Backup.BackupTime.Minute, 0, DateTimeKind.Utc); + NextBackup = BackupTimeOnLocalDay(localToday); //Make sure next backup is in the future if (NextBackup < utcNow) - NextBackup = NextBackup.AddDays(1); + NextBackup = BackupTimeOnLocalDay(localToday.AddDays(1)); } else { //less than 24 hours, set it to tomorrow - NextBackup = new DateTime(utcNow.Year, utcNow.Month, utcNow.Day, Backup.BackupTime.Hour, Backup.BackupTime.Minute, 0, DateTimeKind.Utc); - NextBackup = NextBackup.AddDays(1); + NextBackup = BackupTimeOnLocalDay(localToday.AddDays(1)); } } + //case 4682: the backup time is stored as the UTC moment it meant on the day it was set, and was run at that UTC hour + //every day, so it moved an hour on the server's clock with each daylight saving change. The server's clock time is + //recovered with that day's offset and the backup is run at that clock time on the given local day (UTC returned) + private static DateTime BackupTimeOnLocalDay(DateTime localDay) + { + var chosen = TimeZoneInfo.ConvertTimeFromUtc(DateTime.SpecifyKind(Backup.BackupTime, DateTimeKind.Utc), TimeZoneInfo.Local); + var local = DateTime.SpecifyKind(localDay.Date + new TimeSpan(chosen.Hour, chosen.Minute, 0), DateTimeKind.Unspecified); + //a time skipped when the clocks go forward (e.g. 2:30 AM that night) runs an hour later + if (TimeZoneInfo.Local.IsInvalidTime(local)) + local = local.AddHours(1); + return TimeZoneInfo.ConvertTimeToUtc(local, TimeZoneInfo.Local); + } + }//eoc }//eons \ No newline at end of file