From 02877d6472b61e6063365753b0da622e147b015e Mon Sep 17 00:00:00 2001 From: Teodor Calin Date: Sat, 12 Sep 2026 16:16:38 +0300 Subject: [PATCH] Keep auto-close today valid through the final second Co-authored-by: Martin Monperrus --- CHANGELOG.md | 5 +++++ cmd/shell/autoclose.go | 5 ++++- cmd/shell/autoclose_test.go | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4773d89..7d2ac92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable user-visible changes are recorded here. Versions follow [Semantic Ve ## Unreleased +### Fixed + +- Keep `--auto-close today` valid throughout the final second of the local + day, rather than expiring at the instant that second begins. + ## [0.12.1] — 2026-09-12 ### Added diff --git a/cmd/shell/autoclose.go b/cmd/shell/autoclose.go index 52f382b..1aa92db 100644 --- a/cmd/shell/autoclose.go +++ b/cmd/shell/autoclose.go @@ -215,19 +215,22 @@ func parseAbsoluteDeadline(value string, now time.Time) (time.Time, bool) { // the last minute, so that the form still works during 23:59. clock := "00:00" second := 0 + nanosecond := 0 if prefix == "today" { clock = "23:59" second = 59 + nanosecond = int(time.Second - time.Nanosecond) } if len(value) > len(prefix) { clock = strings.TrimSpace(value[len(prefix):]) second = 0 + nanosecond = 0 } parsedClock, err := time.ParseInLocation("15:04", clock, now.Location()) if err != nil { return time.Time{}, false } - return time.Date(day.Year(), day.Month(), day.Day(), parsedClock.Hour(), parsedClock.Minute(), second, 0, now.Location()), true + return time.Date(day.Year(), day.Month(), day.Day(), parsedClock.Hour(), parsedClock.Minute(), second, nanosecond, now.Location()), true } } diff --git a/cmd/shell/autoclose_test.go b/cmd/shell/autoclose_test.go index 36064e0..b7726d7 100644 --- a/cmd/shell/autoclose_test.go +++ b/cmd/shell/autoclose_test.go @@ -26,7 +26,7 @@ func TestParseCloseDeadline(t *testing.T) { {name: "in prefix", value: "in 15m", want: now.Add(15 * time.Minute)}, {name: "tomorrow", value: "tomorrow 09:15", want: time.Date(2026, time.August, 20, 9, 15, 0, 0, location)}, {name: "bare tomorrow", value: "tomorrow", want: time.Date(2026, time.August, 20, 0, 0, 0, 0, location)}, - {name: "bare today", value: "today", want: time.Date(2026, time.August, 19, 23, 59, 59, 0, location)}, + {name: "bare today", value: "today", want: time.Date(2026, time.August, 19, 23, 59, 59, int(time.Second-time.Nanosecond), location)}, {name: "today with clock", value: "today 23:50", want: time.Date(2026, time.August, 19, 23, 50, 0, 0, location)}, {name: "clock rolls forward", value: "22:00", want: time.Date(2026, time.August, 20, 22, 0, 0, 0, location)}, {name: "local date", value: "2026-08-21 12:30", want: time.Date(2026, time.August, 21, 12, 30, 0, 0, location)}, @@ -127,7 +127,7 @@ func TestNormalizeAutoCloseArgumentsRejectsMissingAndInvalidValues(t *testing.T) func TestBareTodayIsADeadlineAllDay(t *testing.T) { location := time.FixedZone("test", 2*60*60) for _, clock := range []struct{ hour, minute, second int }{ - {0, 0, 0}, {9, 15, 0}, {23, 58, 0}, {23, 59, 30}, + {0, 0, 0}, {9, 15, 0}, {23, 58, 0}, {23, 59, 30}, {23, 59, 59}, } { now := time.Date(2026, time.August, 19, clock.hour, clock.minute, clock.second, 0, location) deadline, err := parseCloseDeadline("today", now)