# calendar-grid ## Purpose `calendar-grid` provides `getCalendarMonth`, which builds a full calendar month grid for use in UI calendar components and scheduling displays. It returns a `CalendarMonth` value containing one `CalendarDay` entry per day in the month, each annotated with its day-of-week index, whether it is a weekend, and whether it represents today (driven by an injectable `Clock`). The module is intentionally narrow: it answers "what are the days in this month and which one is today?" — layout concerns (week rows, leading/trailing days from adjacent months) are left to the consumer. ## Features - `getCalendarMonth` — builds a `CalendarMonth` grid for a given year and 1-indexed month - Each `CalendarDay` includes `date`, `dayOfWeek` (0=Sun … 6=Sat), `isWeekend`, and `isToday` - Injectable `Clock` for deterministic rendering in tests and server-side snapshots - Zero side effects; all computation is local ## Usage: Basic Example ```ts import { getCalendarMonth } from "@suaveplan/datetime"; const march = getCalendarMonth(2024, 3); console.log(march.days.length); // 31 console.log(march.days[0]?.dayOfWeek); // 5 (Friday — Mar 1 2024) const weekends = march.days.filter((d) => d.isWeekend); console.log(weekends.length); // 10 ``` ## Usage: Advanced Example ```ts import { getCalendarMonth } from "@suaveplan/datetime"; // Deterministic "today" for SSR or snapshot tests const fakeClock = () => new Date(2024, 2, 15).getTime(); // Mar 15 2024 const march = getCalendarMonth(2024, 3, { clock: fakeClock }); const today = march.days.find((d) => d.isToday); console.log(today?.date.getDate()); // 15 // Render a simple ASCII calendar header for (const day of march.days) { const marker = day.isToday ? "*" : day.isWeekend ? "W" : " "; process.stdout.write(`${marker}${String(day.date.getDate()).padStart(2)} `); if (day.dayOfWeek === 6) process.stdout.write("\n"); } ``` ## API Reference ### `CalendarMonthOptions` ```ts interface CalendarMonthOptions { clock?: Clock; } ``` - `clock` — injectable `Clock` (returns epoch ms). Defaults to `Date.now`. ### `getCalendarMonth(year: number, month: number, opts?: CalendarMonthOptions): CalendarMonth` Build a `CalendarMonth` for the given `year` and 1-indexed `month`. **Params:** - `year` — full calendar year (e.g. 2024) - `month` — 1-indexed month (1 = January, 12 = December) - `opts.clock` — optional injectable clock **Returns:** `{ year, month, days: CalendarDay[] }` where each `CalendarDay` is: ```ts { date: Date; dayOfWeek: Weekday; isWeekend: boolean; isToday: boolean } ``` ## Implementation Notes `isToday` is computed by comparing a `"year-month-date"` string derived from `clock()` to the same string for each grid day. This string comparison avoids UTC/local timezone confusion that would arise from comparing epoch timestamps directly. The `clock` default (`Date.now`) is captured once per call to ensure consistent "today" across all days in the grid.