first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
# 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.