Some checks failed
Deploy to Cloudflare Workers / deploy (push) Has been cancelled
62 lines
1.7 KiB
TypeScript
62 lines
1.7 KiB
TypeScript
export function startOfMonth(d: Date) {
|
|
return new Date(d.getFullYear(), d.getMonth(), 1);
|
|
}
|
|
|
|
export function endOfMonth(d: Date) {
|
|
return new Date(d.getFullYear(), d.getMonth() + 1, 0, 23, 59, 59, 999);
|
|
}
|
|
|
|
export function addMonths(d: Date, n: number) {
|
|
return new Date(d.getFullYear(), d.getMonth() + n, 1);
|
|
}
|
|
|
|
export function sameDay(a: Date, b: Date) {
|
|
return (
|
|
a.getFullYear() === b.getFullYear() &&
|
|
a.getMonth() === b.getMonth() &&
|
|
a.getDate() === b.getDate()
|
|
);
|
|
}
|
|
|
|
export function toDateKey(d: Date) {
|
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
}
|
|
|
|
export function parseDateKey(key: string) {
|
|
const [y, m, day] = key.split("-").map(Number);
|
|
return new Date(y, m - 1, day);
|
|
}
|
|
|
|
/** Monday-first calendar grid cells (includes leading/trailing days). */
|
|
export function buildMonthGrid(month: Date): Date[] {
|
|
const start = startOfMonth(month);
|
|
const end = endOfMonth(month);
|
|
const startPad = (start.getDay() + 6) % 7;
|
|
const cells: Date[] = [];
|
|
const gridStart = new Date(start);
|
|
gridStart.setDate(start.getDate() - startPad);
|
|
|
|
for (let i = 0; i < 42; i++) {
|
|
const cell = new Date(gridStart);
|
|
cell.setDate(gridStart.getDate() + i);
|
|
cells.push(cell);
|
|
if (i >= 27 && cell >= end && cell.getDay() === 0) break;
|
|
}
|
|
return cells;
|
|
}
|
|
|
|
export function formatMonthYear(d: Date) {
|
|
return d.toLocaleDateString("en-US", { month: "long", year: "numeric" });
|
|
}
|
|
|
|
export function matchDisplayDate(iso: string | null) {
|
|
if (!iso) return "TBD";
|
|
return new Date(iso).toLocaleString(undefined, {
|
|
weekday: "short",
|
|
month: "short",
|
|
day: "numeric",
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
});
|
|
}
|