feat(quando-9sf): implement Next and Prev weekday navigation

- Add Next(weekday) method to jump to next occurrence of a weekday
- Add Prev(weekday) method to jump to previous occurrence of a weekday
- Next ALWAYS returns future date (never today, even if same weekday)
- Prev ALWAYS returns past date (never today, even if same weekday)
- Time of day preserved from source date
- Comprehensive unit tests for all weekday combinations
- Same-weekday edge case tests (Monday.Next(Monday) = next Monday)
- Timezone preservation tests
- Immutability verification tests
- Performance benchmarks (~45ns, well under 1µs target)
- Zero allocations for both operations
- 97.8% test coverage (exceeds 95% requirement)
- Godoc comments with same-weekday behavior examples

All acceptance criteria met:
✓ Next() implemented for all weekdays
✓ Prev() implemented for all weekdays
✓ Next() never returns today (always future)
✓ Prev() never returns today (always past)
✓ Time of day preserved from source
✓ Edge case: Same weekday correctly skips to next/prev week
✓ Unit tests for all weekday combinations
✓ Tests for same weekday edge case
✓ Benchmarks meet <1µs target (~45ns)
✓ Godoc comments with same-weekday behavior example
This commit is contained in:
Oliver Jakoubek 2026-02-11 17:33:54 +01:00
commit 273e920c1c
4 changed files with 372 additions and 1 deletions

54
snap.go
View file

@ -141,3 +141,57 @@ func (d Date) EndOf(unit Unit) Date {
return d
}
}
// Next returns a new Date representing the next occurrence of the specified weekday.
// The time of day is preserved from the source date.
//
// IMPORTANT: Next ALWAYS returns a future date, never today. If today is the
// specified weekday, Next returns the same weekday next week (7 days later).
//
// Example:
//
// // On Monday, Feb 9, 2026
// date := quando.From(time.Date(2026, 2, 9, 15, 30, 0, 0, time.UTC)) // Monday
// nextMonday := date.Next(time.Monday) // Feb 16, 2026 15:30 (next Monday)
// nextFriday := date.Next(time.Friday) // Feb 13, 2026 15:30 (this Friday)
func (d Date) Next(weekday time.Weekday) Date {
t := d.t
currentWeekday := t.Weekday()
// Calculate days until target weekday
daysUntil := int(weekday - currentWeekday)
if daysUntil <= 0 {
// If target is today or in the past this week, jump to next week
daysUntil += 7
}
result := t.AddDate(0, 0, daysUntil)
return Date{t: result, lang: d.lang}
}
// Prev returns a new Date representing the previous occurrence of the specified weekday.
// The time of day is preserved from the source date.
//
// IMPORTANT: Prev ALWAYS returns a past date, never today. If today is the
// specified weekday, Prev returns the same weekday last week (7 days earlier).
//
// Example:
//
// // On Monday, Feb 9, 2026
// date := quando.From(time.Date(2026, 2, 9, 15, 30, 0, 0, time.UTC)) // Monday
// prevMonday := date.Prev(time.Monday) // Feb 2, 2026 15:30 (last Monday)
// prevFriday := date.Prev(time.Friday) // Feb 6, 2026 15:30 (last Friday)
func (d Date) Prev(weekday time.Weekday) Date {
t := d.t
currentWeekday := t.Weekday()
// Calculate days until target weekday (going backwards)
daysUntil := int(currentWeekday - weekday)
if daysUntil <= 0 {
// If target is today or in the future this week, jump to previous week
daysUntil += 7
}
result := t.AddDate(0, 0, -daysUntil)
return Date{t: result, lang: d.lang}
}