// 백엔드 end_time 은 naive UTC ISO(타임존 표기 없음) → 'Z' 를 붙여 UTC 로 파싱한다. const KST_OFFSET_MS = 9 * 60 * 60 * 1000; // UTC 절대시각(ms) → 한국시간(KST) 기준 '그 날짜의 자정'을 UTC ms 앵커로 반환. // +9h 시프트 후 UTC 게터로 읽으면 KST 벽시계 날짜가 된다(브라우저 타임존과 무관하게 항상 KST). function kstDayStart(ms: number): number { const shifted = new Date(ms + KST_OFFSET_MS); return Date.UTC(shifted.getUTCFullYear(), shifted.getUTCMonth(), shifted.getUTCDate()); } // 마감까지 남은 '한국시간 캘린더 일수'로 D-n 표기. 경과시간이 아니라 날짜 차이라 // 오늘 마감(시각 무관)은 항상 D-DAY, 내일이면 D-1. export function fmtDeadline(s?: string | null): string { if (!s) return ''; const due = new Date(s.endsWith('Z') ? s : `${s}Z`); if (Number.isNaN(due.getTime())) return ''; const days = Math.round((kstDayStart(due.getTime()) - kstDayStart(Date.now())) / 86_400_000); if (days < 0) return '지남'; if (days === 0) return 'D-DAY'; return `D-${days}`; }