Files
skills/docs/foundation/timing/datetime/src/calendar/calendar-grid.md
2026-05-29 08:20:56 +01:00

2.9 KiB

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

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

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

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:

{ 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.