diff --git a/internal/modules/lolschedule/format.go b/internal/modules/lolschedule/format.go index 582e0fa..1c02714 100644 --- a/internal/modules/lolschedule/format.go +++ b/internal/modules/lolschedule/format.go @@ -212,7 +212,7 @@ func RenderToday(events []ScheduleEvent, day time.Time) string { return header + "\n\n" + strings.Join(sections, "\n\n") } -// RenderWeek renders the next-7-days reply — grouped by league → day. +// RenderWeek renders a week-range reply — grouped by league → day. // `to` is exclusive (the start of the day after the range), so the label // uses to-1. func RenderWeek(events []ScheduleEvent, from, to time.Time) string { diff --git a/internal/modules/lolschedule/handlers.go b/internal/modules/lolschedule/handlers.go index 9828710..9e9817e 100644 --- a/internal/modules/lolschedule/handlers.go +++ b/internal/modules/lolschedule/handlers.go @@ -58,13 +58,14 @@ func (s *state) handleToday(ctx context.Context, b *bot.Bot, update *models.Upda return s.replyForRange(ctx, b, msg, from, addDays(from, 1), false) } -// handleWeek is /lolschedule_week — next 7 ICT days. +// handleWeek is /lolschedule_week — the current ICT calendar week +// (Monday 00:00 ICT through the following Monday 00:00 ICT, exclusive). func (s *state) handleWeek(ctx context.Context, b *bot.Bot, update *models.Update) error { msg := update.Message if msg == nil { return nil } - from := ictDayStartOf(s.now()) + from := ictWeekStartOf(s.now()) return s.replyForRange(ctx, b, msg, from, addDays(from, 7), true) } diff --git a/internal/modules/lolschedule/handlers_test.go b/internal/modules/lolschedule/handlers_test.go index 9a927cb..af52211 100644 --- a/internal/modules/lolschedule/handlers_test.go +++ b/internal/modules/lolschedule/handlers_test.go @@ -110,6 +110,12 @@ func TestHandleWeek_RendersWeek(t *testing.T) { if !strings.Contains(got, "→") { t.Errorf("week header missing arrow: %q", got) } + // fakeNowMs is Sat 2026-05-09 ICT → calendar week is Mon May 4 → Sun May 10. + for _, want := range []string{"Mon May 4", "Sun May 10"} { + if !strings.Contains(got, want) { + t.Errorf("week header missing %q in:\n%s", want, got) + } + } } func TestHandleSubscribe_AddsAndIsIdempotent(t *testing.T) { diff --git a/internal/modules/lolschedule/lolschedule.go b/internal/modules/lolschedule/lolschedule.go index ecfadef..82c48a6 100644 --- a/internal/modules/lolschedule/lolschedule.go +++ b/internal/modules/lolschedule/lolschedule.go @@ -28,7 +28,7 @@ func New(deps modules.Deps) modules.Module { { Name: "lolschedule_week", Visibility: modules.VisibilityPublic, - Description: "LoL esports matches for the next 7 days", + Description: "LoL esports matches for this week (Mon–Sun, ICT)", Handler: s.handleWeek, }, { diff --git a/internal/modules/lolschedule/parse_date.go b/internal/modules/lolschedule/parse_date.go index 6ea957b..509d81b 100644 --- a/internal/modules/lolschedule/parse_date.go +++ b/internal/modules/lolschedule/parse_date.go @@ -36,6 +36,17 @@ func ictDayStartOf(now time.Time) time.Time { return dayStart.UTC() } +// ictWeekStartOf returns the start of the ICT calendar week (Monday 00:00 ICT) +// containing now, expressed as a UTC instant. Week boundary is ISO 8601: +// Monday is day 1, Sunday is day 7. +func ictWeekStartOf(now time.Time) time.Time { + day := ictDayStartOf(now).In(IctLocation) + // time.Weekday: Sunday=0, Monday=1, ..., Saturday=6. + // Days since Monday: Mon→0, Tue→1, ..., Sun→6. + daysFromMonday := (int(day.Weekday()) + 6) % 7 + return day.AddDate(0, 0, -daysFromMonday).UTC() +} + // addDays returns date + days, preserving time-of-day. func addDays(date time.Time, days int) time.Time { return date.Add(time.Duration(days) * 24 * time.Hour) diff --git a/internal/modules/lolschedule/parse_date_test.go b/internal/modules/lolschedule/parse_date_test.go index 2b4af04..501731b 100644 --- a/internal/modules/lolschedule/parse_date_test.go +++ b/internal/modules/lolschedule/parse_date_test.go @@ -106,6 +106,28 @@ func TestIctDayStartOf(t *testing.T) { } } +func TestIctWeekStartOf(t *testing.T) { + // refNow is Sat 2026-05-09 19:00 ICT. Monday of that ICT week is + // 2026-05-04 00:00 ICT = 2026-05-03 17:00 UTC. + wantMon := time.Date(2026, 5, 3, 17, 0, 0, 0, time.UTC) + if got := ictWeekStartOf(refNow); !got.Equal(wantMon) { + t.Errorf("ictWeekStartOf(Sat) = %v, want %v", got, wantMon) + } + + // When `now` IS a Monday, week start is that same Monday. + mon := time.Date(2026, 5, 4, 8, 0, 0, 0, IctLocation) // Mon 2026-05-04 08:00 ICT + wantSameMon := time.Date(2026, 5, 4, 0, 0, 0, 0, IctLocation).UTC() + if got := ictWeekStartOf(mon); !got.Equal(wantSameMon) { + t.Errorf("ictWeekStartOf(Mon) = %v, want %v", got, wantSameMon) + } + + // Sunday belongs to the same ISO week as the preceding Monday. + sun := time.Date(2026, 5, 10, 23, 0, 0, 0, IctLocation) // Sun 2026-05-10 23:00 ICT + if got := ictWeekStartOf(sun); !got.Equal(wantSameMon) { + t.Errorf("ictWeekStartOf(Sun) = %v, want %v", got, wantSameMon) + } +} + func TestAddDays(t *testing.T) { base := time.Date(2026, 5, 9, 12, 30, 0, 0, time.UTC) got := addDays(base, 3)