// frontend/lib/calendar/time.ts — cal.jsx 의 toMin/fmt/topOf 이식 export const HSTART = 7; export const PXH = 52; export const HOURS = Array.from({ length: 16 }, (_, i) => 7 + i); // 7..22 export const toMin = (t: string): number => { const [h, m] = t.split(":").map(Number); return h * 60 + m; }; // 분 → "HH:MM"(자정~23:59 캡). 드래그 이동/리사이즈 결과 계산용. export const fromMin = (total: number): string => { const t = Math.max(0, Math.min(total, 23 * 60 + 59)); const h = Math.floor(t / 60); const m = t % 60; return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`; }; export const GRID_END_MIN = (HSTART + HOURS.length) * 60; // 23:00 (그리드 하단) export const fmt = (t: string): string => { const [h, m] = t.split(":").map(Number); const ap = h < 12 ? "오전" : "오후"; const hh = h % 12 === 0 ? 12 : h % 12; return `${ap} ${hh}:${String(m).padStart(2, "0")}`; }; export const topOf = (t: string): number => ((toMin(t) - HSTART * 60) / 60) * PXH; // 그리드 내부 Y 픽셀 → "HH:MM"(30분 단위 반올림). 슬롯 클릭 생성용. export const timeOfPx = (y: number): string => { const totalMin = HSTART * 60 + (y / PXH) * 60; const lastMin = (HSTART + HOURS.length) * 60; // 22:00 const snapped = Math.round(totalMin / 30) * 30; const clamped = Math.max(HSTART * 60, Math.min(snapped, lastMin - 60)); const h = Math.floor(clamped / 60); const m = clamped % 60; return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`; }; // "HH:MM" + n시간 → "HH:MM"(24시 캡). 생성 시 종료시각 계산용. export const addHour = (t: string, n: number): string => { const total = Math.min(toMin(t) + n * 60, 23 * 60 + 59); const h = Math.floor(total / 60); const m = total % 60; return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`; }; // ── 실제 날짜(ISO "YYYY-MM-DD") 유틸 ────────────────────────────── export const parseISO = (iso: string): Date => { const [y, m, d] = iso.split("-").map(Number); return new Date(y, (m || 1) - 1, d || 1); }; export const isoOf = (d: Date): string => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`; export const addDays = (iso: string, n: number): string => { const d = parseISO(iso); d.setDate(d.getDate() + n); return isoOf(d); }; export const addMonths = (iso: string, n: number): string => { const d = parseISO(iso); d.setDate(1); d.setMonth(d.getMonth() + n); return isoOf(d); }; export const startOfWeek = (iso: string): string => { const d = parseISO(iso); d.setDate(d.getDate() - d.getDay()); // 일요일 시작 return isoOf(d); }; export const weekDatesOf = (iso: string): string[] => { const s = startOfWeek(iso); return Array.from({ length: 7 }, (_, i) => addDays(s, i)); }; export const dayNum = (iso: string): number => parseISO(iso).getDate(); export const monthNum = (iso: string): number => parseISO(iso).getMonth() + 1; export const yearNum = (iso: string): number => parseISO(iso).getFullYear(); // 월 그리드(42칸): 해당 월 1일이 포함된 주(일요일)부터 6주. export const monthCells = (iso: string): { date: string; inMonth: boolean }[] => { const ref = parseISO(iso); const first = new Date(ref.getFullYear(), ref.getMonth(), 1); const startIso = startOfWeek(isoOf(first)); return Array.from({ length: 42 }, (_, i) => { const date = addDays(startIso, i); return { date, inMonth: monthNum(date) === ref.getMonth() + 1 }; }); };