/** * 달력 유틸리티 함수 */ // 한국 공휴일 데이터 (2025년 기준) export interface Holiday { date: string; // 'MM-DD' 형식 name: string; isRecurring: boolean; } export const KOREAN_HOLIDAYS: Holiday[] = [ { date: "01-01", name: "신정", isRecurring: true }, { date: "01-28", name: "설날 연휴", isRecurring: false }, { date: "01-29", name: "설날", isRecurring: false }, { date: "01-30", name: "설날 연휴", isRecurring: false }, { date: "03-01", name: "삼일절", isRecurring: true }, { date: "05-05", name: "어린이날", isRecurring: true }, { date: "06-06", name: "현충일", isRecurring: true }, { date: "08-15", name: "광복절", isRecurring: true }, { date: "10-03", name: "개천절", isRecurring: true }, { date: "10-09", name: "한글날", isRecurring: true }, { date: "12-25", name: "크리스마스", isRecurring: true }, ]; /** * 특정 월의 첫 날 Date 객체 반환 */ export function getFirstDayOfMonth(year: number, month: number): Date { return new Date(year, month, 1); } /** * 특정 월의 마지막 날짜 반환 */ export function getLastDateOfMonth(year: number, month: number): number { return new Date(year, month + 1, 0).getDate(); } /** * 특정 월의 첫 날의 요일 반환 (0=일요일, 1=월요일, ...) */ export function getFirstDayOfWeek(year: number, month: number): number { return new Date(year, month, 1).getDay(); } /** * 달력 그리드에 표시할 날짜 배열 생성 * @param year 년도 * @param month 월 (0-11) * @param startWeekOn 주 시작 요일 ('monday' | 'sunday') * @returns 6주 * 7일 = 42개의 날짜 정보 배열 */ export interface CalendarDay { date: Date; day: number; isCurrentMonth: boolean; isToday: boolean; isWeekend: boolean; isHoliday: boolean; holidayName?: string; } export function generateCalendarDays( year: number, month: number, startWeekOn: "monday" | "sunday" = "sunday", ): CalendarDay[] { const days: CalendarDay[] = []; const firstDay = getFirstDayOfWeek(year, month); const lastDate = getLastDateOfMonth(year, month); const today = new Date(); today.setHours(0, 0, 0, 0); // 시작 오프셋 계산 let startOffset = firstDay; if (startWeekOn === "monday") { startOffset = firstDay === 0 ? 6 : firstDay - 1; } // 이전 달 날짜들 const prevMonthLastDate = getLastDateOfMonth(year, month - 1); for (let i = startOffset - 1; i >= 0; i--) { const date = new Date(year, month - 1, prevMonthLastDate - i); days.push(createCalendarDay(date, false, today)); } // 현재 달 날짜들 for (let day = 1; day <= lastDate; day++) { const date = new Date(year, month, day); days.push(createCalendarDay(date, true, today)); } // 다음 달 날짜들 (42개 채우기) const remainingDays = 42 - days.length; for (let day = 1; day <= remainingDays; day++) { const date = new Date(year, month + 1, day); days.push(createCalendarDay(date, false, today)); } return days; } /** * CalendarDay 객체 생성 */ function createCalendarDay(date: Date, isCurrentMonth: boolean, today: Date): CalendarDay { const dayOfWeek = date.getDay(); const isToday = date.getTime() === today.getTime(); const isWeekend = dayOfWeek === 0 || dayOfWeek === 6; // 공휴일 체크 const monthStr = String(date.getMonth() + 1).padStart(2, "0"); const dayStr = String(date.getDate()).padStart(2, "0"); const dateKey = `${monthStr}-${dayStr}`; const holiday = KOREAN_HOLIDAYS.find((h) => h.date === dateKey); return { date, day: date.getDate(), isCurrentMonth, isToday, isWeekend, isHoliday: !!holiday, holidayName: holiday?.name, }; } /** * 요일 이름 배열 반환 */ export function getWeekDayNames(startWeekOn: "monday" | "sunday" = "sunday"): string[] { const sundayFirst = ["일", "월", "화", "수", "목", "금", "토"]; const mondayFirst = ["월", "화", "수", "목", "금", "토", "일"]; return startWeekOn === "monday" ? mondayFirst : sundayFirst; } /** * 월 이름 반환 */ export function getMonthName(month: number): string { const months = ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"]; return months[month]; } /** * 이전/다음 월로 이동 */ export function navigateMonth(year: number, month: number, direction: "prev" | "next"): { year: number; month: number } { if (direction === "prev") { if (month === 0) { return { year: year - 1, month: 11 }; } return { year, month: month - 1 }; } else { if (month === 11) { return { year: year + 1, month: 0 }; } return { year, month: month + 1 }; } }