From df278007bf4d354b89af0074deb33454b655437a Mon Sep 17 00:00:00 2001 From: jessikitty Date: Sun, 23 Aug 2026 00:05:11 +1000 Subject: [PATCH] Add time-zone-aware Clock helper for Meow expiry checks --- Infrastructure/Clock.cs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Infrastructure/Clock.cs diff --git a/Infrastructure/Clock.cs b/Infrastructure/Clock.cs new file mode 100644 index 0000000..5c21d66 --- /dev/null +++ b/Infrastructure/Clock.cs @@ -0,0 +1,40 @@ +namespace NoticeBoard.Infrastructure; + +/// +/// Single source of "now" for Meow expiry checks, so the picker (browser wall-clock, +/// no time zone info) and the server's comparison always agree on what "now" means. +/// +/// Configured once at startup from the "TimeZone" setting (an IANA id like +/// "Australia/Melbourne", or "UTC"). Leaving it blank falls back to the host +/// machine's own local time zone — the original IIS behaviour, unchanged. +/// +public static class Clock +{ + private static TimeZoneInfo _timeZone = TimeZoneInfo.Local; + + public static void Configure(string? timeZoneId) + { + if (string.IsNullOrWhiteSpace(timeZoneId)) + { + _timeZone = TimeZoneInfo.Local; + return; + } + + try + { + _timeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId); + } + catch (TimeZoneNotFoundException) + { + // Unknown id (e.g. tzdata missing, or a typo) — UTC is a safe, unambiguous fallback. + _timeZone = TimeZoneInfo.Utc; + } + catch (InvalidTimeZoneException) + { + _timeZone = TimeZoneInfo.Utc; + } + } + + /// Current time in the configured server time zone — directly comparable to a stored ExpiresAt value. + public static DateTime Now => TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, _timeZone); +}