summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-22 14:31:19 +0300
committerPaul Buetow <paul@buetow.org>2026-06-22 14:31:19 +0300
commit58476df487c4d8f56410b112cc551ae663c88d19 (patch)
treec3325938fbb3cdc1c3a26f5cc2a07df41dc47cb8
parenta1407cd9c960da7cb7e13b37ec444590319b8908 (diff)
Fix due date display calendar days (oq0)
-rw-r--r--internal/ui/table.go16
-rw-r--r--internal/ui/table_test.go57
2 files changed, 60 insertions, 13 deletions
diff --git a/internal/ui/table.go b/internal/ui/table.go
index 59eaaeb..2772e2b 100644
--- a/internal/ui/table.go
+++ b/internal/ui/table.go
@@ -1025,23 +1025,13 @@ func (m Model) formatDue(s string, width int) string {
if s == "" {
return ""
}
- ts, err := time.Parse(task.DateFormat, s)
+ ts, err := parseTaskDate(s)
if err != nil {
return s
}
- days := int(time.Until(ts).Hours() / 24)
- var val string
- switch days {
- case 0:
- val = "today"
- case 1:
- val = "tomorrow"
- case -1:
- val = "yesterday"
- default:
- val = fmt.Sprintf("%dd", days)
- }
+ days := daysUntil(ts)
+ val := formatDueText(s)
style := lipgloss.NewStyle().Width(width)
if days < 0 {
style = style.Background(lipgloss.Color(m.theme.OverdueBG))
diff --git a/internal/ui/table_test.go b/internal/ui/table_test.go
index bfd866d..9bc8150 100644
--- a/internal/ui/table_test.go
+++ b/internal/ui/table_test.go
@@ -74,6 +74,63 @@ func TestAnnotateHotkey(t *testing.T) {
}
}
+func TestFormatDueUsesCalendarDayLabels(t *testing.T) {
+ now := time.Now()
+ dueOn := func(dayOffset int, hour, minute int) string {
+ day := now.AddDate(0, 0, dayOffset)
+ due := time.Date(day.Year(), day.Month(), day.Day(), hour, minute, 0, 0, time.UTC)
+ return due.Format(task.DateFormat)
+ }
+ skipIfDateChanged := func() {
+ t.Helper()
+ later := time.Now()
+ if later.Year() != now.Year() || later.YearDay() != now.YearDay() {
+ t.Skip("local date changed during due-date boundary test")
+ }
+ }
+
+ m := Model{theme: DefaultTheme()}
+ tests := []struct {
+ name string
+ due string
+ want string
+ }{
+ {
+ name: "late yesterday",
+ due: dueOn(-1, 23, 59),
+ want: "yesterday",
+ },
+ {
+ name: "early today",
+ due: dueOn(0, 0, 1),
+ want: "today",
+ },
+ {
+ name: "late tomorrow",
+ due: dueOn(1, 23, 59),
+ want: "tomorrow",
+ },
+ {
+ name: "future day count",
+ due: dueOn(3, 23, 59),
+ want: "3d",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := strings.TrimSpace(ansi.Strip(m.formatDue(tt.due, 12)))
+ skipIfDateChanged()
+ if got != tt.want {
+ t.Fatalf("formatDue() = %q, want %q", got, tt.want)
+ }
+ if got != formatDueText(tt.due) {
+ t.Fatalf("formatDue() = %q, formatDueText() = %q", got, formatDueText(tt.due))
+ }
+ })
+ }
+}
+
func TestReplaceAnnotationHotkey(t *testing.T) {
tmp := t.TempDir()
taskPath := filepath.Join(tmp, "task")