From 121f755f862adedbafc50a9cb9ca7ec7f36a5fc2 Mon Sep 17 00:00:00 2001 From: Daniel Chalmers Date: Fri, 10 Jul 2026 20:40:19 -0500 Subject: [PATCH 1/2] Show a negative sign when a tokenized countdown has passed --- .../TimeStringFormatterTests.cs | 23 +++++++++++++++++++ DesktopClock/Utilities/TimeStringFormatter.cs | 9 +++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/DesktopClock.Tests/TimeStringFormatterTests.cs b/DesktopClock.Tests/TimeStringFormatterTests.cs index 88ea69b..1bcf2ee 100644 --- a/DesktopClock.Tests/TimeStringFormatterTests.cs +++ b/DesktopClock.Tests/TimeStringFormatterTests.cs @@ -81,6 +81,29 @@ public void Format_UsesCountdownFormatWhenProvided() Assert.Equal((countdownTo - nowDateTime).ToString("c", formatProvider), result); } + [Theory] + [InlineData("{hh\\:mm\\:ss}", "-01:30:00")] // Tokenized custom format + [InlineData("{%h}h {%m}m", "-1h 30m")] // Tokenized preset style + [InlineData("c", "-01:30:00")] // Standard format keeps a single sign + [InlineData("{bad}", "Bad format")] // Errors are not prefixed + public void Format_PastCountdownShowsNegativeSign(string countdownFormat, string expected) + { + var now = new DateTimeOffset(2024, 1, 1, 10, 0, 0, TimeSpan.Zero); + var nowDateTime = now.DateTime; + var countdownTo = nowDateTime.AddMinutes(-90); + + var result = TimeStringFormatter.Format( + now, + nowDateTime, + TimeZoneInfo.Utc, + countdownTo, + "HH:mm", + countdownFormat, + CultureInfo.InvariantCulture); + + Assert.Equal(expected, result); + } + [Fact] public void Format_UsesHumanizerWhenCountdownFormatMissing() { diff --git a/DesktopClock/Utilities/TimeStringFormatter.cs b/DesktopClock/Utilities/TimeStringFormatter.cs index cfa6ef6..d0dc951 100644 --- a/DesktopClock/Utilities/TimeStringFormatter.cs +++ b/DesktopClock/Utilities/TimeStringFormatter.cs @@ -29,7 +29,14 @@ public static string Format( else { var countdown = countdownTo - nowDateTime; - result = Tokenizer.FormatWithTokenizerOrFallBack(countdown, countdownFormat, formatProvider); + + // Custom TimeSpan formats drop the sign, so format the magnitude and add the sign back + // to keep an elapsed target from reading like time remaining. + var isElapsed = countdown < TimeSpan.Zero; + result = Tokenizer.FormatWithTokenizerOrFallBack(isElapsed ? countdown.Negate() : countdown, countdownFormat, formatProvider); + + if (isElapsed && result != Tokenizer.FormatErrorMessage) + result = "-" + result; } return result; From 89834fcf8b27bc2ec6de7edd674b5456977edc6e Mon Sep 17 00:00:00 2001 From: Daniel Chalmers Date: Fri, 10 Jul 2026 20:44:45 -0500 Subject: [PATCH 2/2] Condense comment --- DesktopClock/Utilities/TimeStringFormatter.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/DesktopClock/Utilities/TimeStringFormatter.cs b/DesktopClock/Utilities/TimeStringFormatter.cs index d0dc951..ca35437 100644 --- a/DesktopClock/Utilities/TimeStringFormatter.cs +++ b/DesktopClock/Utilities/TimeStringFormatter.cs @@ -30,8 +30,7 @@ public static string Format( { var countdown = countdownTo - nowDateTime; - // Custom TimeSpan formats drop the sign, so format the magnitude and add the sign back - // to keep an elapsed target from reading like time remaining. + // Custom TimeSpan formats drop the sign, so format the magnitude and add it back to mark an elapsed target. var isElapsed = countdown < TimeSpan.Zero; result = Tokenizer.FormatWithTokenizerOrFallBack(isElapsed ? countdown.Negate() : countdown, countdownFormat, formatProvider);