---
type: snippet
kind: Convention
title: dayjs 날짜 표기 카탈로그
description: 허용 날짜 표기를 as const 배열 하나로 고정하고 union 타입을 파생시킨다. 매핑 객체는 필요 없다.
resource: /src/lib/date.ts
tags: ['typescript', 'dayjs', 'date-format', 'type-safety']
status: release
ctime: 2026-06-28
mtime: 2026-09-10
generated: { by: claude/opus-5, at: 2026-09-01T00:00:00Z }
verified: { by: human:cbcruk, at: 2026-08-19T00:00:00Z }
stale_after: 2027-07-27
sources:
  - id: dayjs-format
    resource: https://day.js.org/docs/en/display/format
    title: dayjs — Format
  - id: dayjs-i18n
    resource: https://day.js.org/docs/en/i18n/loading-into-nodejs
    title: dayjs — Loading locale
---

날짜 표기 통일에 **매핑 객체가 필요 없다** — dayjs는 포맷 문자열이 곧 키이자 값이다.[^dayjs-format]
i18n은 이름표(`인사`)와 내용(`Hello`)이 달라서 짝지어주는 객체가 필수였다. 그 습관이 여기까지 따라온 것이다.

**언제** — 날짜 표기를 받는 인자를 타입으로 닫을 때. 표기 이름과 포맷 문자열을 짝지을 매핑 객체부터 떠오르면 그게 신호다.

# Schema

| 이름 | 형태 | 역할 |
|---|---|---|
| `DATE_FORMATS` | `readonly string[]` (`as const`) | 허용 표기의 단일 출처 |
| `DateFormat` | `(typeof DATE_FORMATS)[number]` | 배열에서 파생된 닫힌 union |
| `formatDate` | `(date, format: DateFormat) => string` | 유일한 진입점 |

# Examples

```ts
import dayjs from 'dayjs'

export const DATE_FORMATS = [
  'YYYY-MM-DD',
  'YYYY-MM-DDTHH:mm:ss',
  'HH:mm',
  'YYYY년 M월',
  'YY년 M월 D일',
  'YYYY.MM.DD',
  'YY.MM.DD',
  'YYYY.MM.DD(ddd)',
  'YYYY.MM.DD HH:mm',
] as const

export type DateFormat = (typeof DATE_FORMATS)[number]

export const formatDate = (
  date: dayjs.ConfigType,
  format: DateFormat,
): string => dayjs(date).format(format)
```

# 표기 추가하기

**언제**: 카탈로그에 없는 표기가 필요할 때.

**절차**

1. **여러 곳에서 통일이 필요한 표기인가.** 일회성(`'M.D'` 등)이면 여기서 멈추고 raw
   `dayjs().format()`으로 인라인 유지한다 — 이 기준이 없으면 배열이 잡동사니 enum이 된다.
2. `DATE_FORMATS`에 추가한다. `DateFormat`은 배열에서 파생되므로 따로 손댈 곳이 없다.
3. `ddd`가 들어 있으면 진입점에 `dayjs.locale('ko')`가 있는지 확인한다.[^dayjs-i18n]

**확인**: 카탈로그에 있는 표기를 `formatDate`를 우회해 raw로 다시 쓴 곳이 없는가.
**타입은 이걸 못 막는다** — [no-raw-date-format](/rules/no-raw-date-format.md)
(`no-restricted-syntax`)이 필요한데 아직 작성하지 않았다. 그 규칙이 없으면 카탈로그의
단일 출처 지위는 관행일 뿐이다.

**함정**: `dayjs.locale('ko')` 없이 `ddd`를 쓰면 `Mon`·`Tue`처럼 영어로 **조용히** 샌다 —
예외도 타입 오류도 없다. `YYYY.MM.DD(ddd)`는 그래서 다른 표기와 달리 런타임 전제를 가진
항목이다.

# 기각: 빌드타임 hoist / tagged-template 캐시

포맷 문자열을 빌드 때 미리 계산해 상수로 끌어올리거나(hoist) 결과를 캐시해두는
방법을 검토했다. 고유 패턴이 수십 개 규모라 중복 제거로도 컴파일 최적화로도 얻을 게
없다. 닫힌 타입 + 함수 하나로 충분하다. 패턴 수가 수백 단위로 늘면 재검토한다.

[^dayjs-format]: dayjs — Format
[^dayjs-i18n]: dayjs — Loading locale
