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); }