/** * ISO 8601 주차 계산 composable */ interface WeekInfo { year: number week: number startDate: Date endDate: Date startDateStr: string endDateStr: string weekString: string // "2026-W01" 형식 } export function useWeekCalc() { /** * 특정 날짜의 ISO 주차 정보 반환 */ function getWeekInfo(date: Date = new Date()): WeekInfo { const target = new Date(date) target.setHours(0, 0, 0, 0) // 목요일 기준으로 연도 판단 (ISO 규칙) const thursday = new Date(target) thursday.setDate(target.getDate() - ((target.getDay() + 6) % 7) + 3) const year = thursday.getFullYear() const firstThursday = new Date(year, 0, 4) firstThursday.setDate(firstThursday.getDate() - ((firstThursday.getDay() + 6) % 7) + 3) const week = Math.ceil((thursday.getTime() - firstThursday.getTime()) / (7 * 24 * 60 * 60 * 1000)) + 1 // 해당 주의 월요일 const monday = new Date(target) monday.setDate(target.getDate() - ((target.getDay() + 6) % 7)) // 해당 주의 일요일 const sunday = new Date(monday) sunday.setDate(monday.getDate() + 6) return { year, week, startDate: monday, endDate: sunday, startDateStr: formatDate(monday), endDateStr: formatDate(sunday), weekString: `${year}-W${week.toString().padStart(2, '0')}` } } /** * 이번 주 정보 (보고서 기준) * - 금~일: 현재 주차 * - 월~목: 이전 주차 */ function getCurrentWeekInfo(): WeekInfo { const today = new Date() const dayOfWeek = today.getDay() // 0=일, 1=월, ..., 5=금, 6=토 // 월~목 (1~4)이면 이전 주차 기준 if (dayOfWeek >= 1 && dayOfWeek <= 4) { const lastWeek = new Date(today) lastWeek.setDate(today.getDate() - 7) return getWeekInfo(lastWeek) } // 금~일 (5, 6, 0)이면 현재 주차 기준 return getWeekInfo(today) } /** * 실제 이번 주 정보 (달력 기준, 항상 현재 주차) */ function getActualCurrentWeekInfo(): WeekInfo { return getWeekInfo(new Date()) } /** * 지난 주 정보 */ function getLastWeekInfo(): WeekInfo { const lastWeek = new Date() lastWeek.setDate(lastWeek.getDate() - 7) return getWeekInfo(lastWeek) } /** * 날짜 포맷 (YYYY-MM-DD) */ function formatDate(date: Date): string { return date.toISOString().split('T')[0] } /** * 주차 문자열 파싱 */ function parseWeekString(weekStr: string): { year: number; week: number } | null { const match = weekStr.match(/^(\d{4})-W(\d{2})$/) if (!match) return null return { year: parseInt(match[1]), week: parseInt(match[2]) } } /** * 주차별 날짜 범위 텍스트 */ function getWeekRangeText(year: number, week: number): string { // 해당 연도 첫 번째 목요일 찾기 const jan4 = new Date(year, 0, 4) const firstThursday = new Date(jan4) firstThursday.setDate(jan4.getDate() - ((jan4.getDay() + 6) % 7) + 3) // 해당 주차의 월요일 const monday = new Date(firstThursday) monday.setDate(firstThursday.getDate() - 3 + (week - 1) * 7) const sunday = new Date(monday) sunday.setDate(monday.getDate() + 6) return `${formatDateKr(monday)} ~ ${formatDateKr(sunday)}` } /** * 한국어 날짜 포맷 (M월 D일) */ function formatDateKr(date: Date): string { return `${date.getMonth() + 1}월 ${date.getDate()}일` } return { getWeekInfo, getCurrentWeekInfo, getActualCurrentWeekInfo, getLastWeekInfo, formatDate, parseWeekString, getWeekRangeText, formatDateKr } }