{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "lib-date",
  "type": "registry:lib",
  "title": "lib/date",
  "description": "날짜는 시간대 문제를 피하기 위해 항상 ISO 날짜 문자열(\"YYYY-MM-DD\")로 다룹니다.",
  "files": [
    {
      "path": "poc/design-system/implement/src/lib/date.ts",
      "content": "/**\n * 날짜는 시간대 문제를 피하기 위해 항상 ISO 날짜 문자열(\"YYYY-MM-DD\")로 다룹니다.\n * 계산은 UTC 기준 Date 로만 하고, 결과는 다시 문자열로 돌려줍니다.\n */\nexport type ISODate = string;\n\nconst ISO_RE = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\nconst WEEKDAYS_KO = [\"일\", \"월\", \"화\", \"수\", \"목\", \"금\", \"토\"] as const;\n\nfunction pad(n: number, len = 2) {\n  return String(n).padStart(len, \"0\");\n}\n\nfunction toUTC(iso: ISODate): Date {\n  const [, y, m, d] = ISO_RE.exec(iso)!;\n  return new Date(Date.UTC(Number(y), Number(m) - 1, Number(d)));\n}\n\nfunction fromUTC(date: Date): ISODate {\n  return `${pad(date.getUTCFullYear(), 4)}-${pad(date.getUTCMonth() + 1)}-${pad(date.getUTCDate())}`;\n}\n\nexport function isValidISODate(value: string): boolean {\n  if (!ISO_RE.test(value)) return false;\n  return fromUTC(toUTC(value)) === value; // 2026-02-30 같은 값 걸러냄\n}\n\nexport function todayISO(): ISODate {\n  const now = new Date();\n  return `${pad(now.getFullYear(), 4)}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;\n}\n\nexport function dateParts(iso: ISODate) {\n  const d = toUTC(iso);\n  return { year: d.getUTCFullYear(), month: d.getUTCMonth() + 1, day: d.getUTCDate(), weekday: d.getUTCDay() };\n}\n\nexport function addDays(iso: ISODate, days: number): ISODate {\n  const d = toUTC(iso);\n  d.setUTCDate(d.getUTCDate() + days);\n  return fromUTC(d);\n}\n\n/** 월 이동. 31일 → 다음 달에 없으면 말일로 맞춤 */\nexport function addMonths(iso: ISODate, months: number): ISODate {\n  const { year, month, day } = dateParts(iso);\n  const target = new Date(Date.UTC(year, month - 1 + months, 1));\n  const lastDay = new Date(Date.UTC(target.getUTCFullYear(), target.getUTCMonth() + 1, 0)).getUTCDate();\n  target.setUTCDate(Math.min(day, lastDay));\n  return fromUTC(target);\n}\n\nexport function startOfWeek(iso: ISODate, weekStartsOn: 0 | 1): ISODate {\n  const { weekday } = dateParts(iso);\n  return addDays(iso, -((weekday - weekStartsOn + 7) % 7));\n}\n\nexport function endOfWeek(iso: ISODate, weekStartsOn: 0 | 1): ISODate {\n  return addDays(startOfWeek(iso, weekStartsOn), 6);\n}\n\nexport function firstOfMonth(iso: ISODate): ISODate {\n  return `${iso.slice(0, 7)}-01`;\n}\n\n/** 달력 6주(42칸) 그리드 */\nexport function monthGrid(iso: ISODate, weekStartsOn: 0 | 1): ISODate[][] {\n  let cursor = startOfWeek(firstOfMonth(iso), weekStartsOn);\n  return Array.from({ length: 6 }, () =>\n    Array.from({ length: 7 }, () => {\n      const day = cursor;\n      cursor = addDays(cursor, 1);\n      return day;\n    }),\n  );\n}\n\nexport function sameMonth(a: ISODate, b: ISODate) {\n  return a.slice(0, 7) === b.slice(0, 7);\n}\n\nexport function weekdayLabels(weekStartsOn: 0 | 1) {\n  return [...WEEKDAYS_KO.slice(weekStartsOn), ...WEEKDAYS_KO.slice(0, weekStartsOn)];\n}\n\n/** 스크린리더용: \"2026년 10월 2일 금요일\" */\nexport function formatLong(iso: ISODate) {\n  const { year, month, day, weekday } = dateParts(iso);\n  return `${year}년 ${month}월 ${day}일 ${WEEKDAYS_KO[weekday]}요일`;\n}\n\nexport function formatMonthTitle(iso: ISODate) {\n  const { year, month } = dateParts(iso);\n  return `${year}년 ${month}월`;\n}\n\n/** 숫자만 입력해도 \"-\" 를 넣어줌: \"20261002\" → \"2026-10-02\" */\nexport function maskDate(raw: string): string {\n  const digits = raw.replace(/\\D/g, \"\").slice(0, 8);\n  return [digits.slice(0, 4), digits.slice(4, 6), digits.slice(6, 8)].filter(Boolean).join(\"-\");\n}\n\n/** 기간 입력 마스크: \"2026100220261009\" → \"2026-10-02 ~ 2026-10-09\" */\nexport function maskDateRange(raw: string): string {\n  const digits = raw.replace(/\\D/g, \"\").slice(0, 16);\n  const start = maskDate(digits.slice(0, 8));\n  const end = maskDate(digits.slice(8));\n  return end ? `${start} ~ ${end}` : start;\n}\n",
      "type": "registry:lib",
      "target": "components/lib/date.ts"
    }
  ],
  "categories": [
    "internal"
  ],
  "meta": {
    "version": "0.1.0"
  }
}
