[EXT-024][실무] 시작일과 종료일을 한 줄로 자연스럽게 표시하기 > IT 기술 공유

본문 바로가기
사이트 내 전체검색

IT 기술 공유

[EXT-024][실무] 시작일과 종료일을 한 줄로 자연스럽게 표시하기

페이지 정보

profile_image
작성자 기술팀장
댓글 0건 조회 8회 작성일 26-09-08 14:38

본문

[이번 수업]

행사나 예약의 시작일과 종료일을 각각 만든 문자열로 이어 붙이지 않고, JavaScript의 Intl.DateTimeFormat.formatRange()로 한 줄에 표시합니다. 언어별 날짜 순서와 구분 기호를 적용하고 공통 부분을 줄이는 방법을 배웁니다.

[선수지식]

Date 객체, ISO 8601 형태의 시각 문자열, 로케일과 시간대의 뜻을 알면 됩니다. 날짜 범위는 시작과 종료라는 두 경계를 가진 데이터입니다.

[학습목표]

1. formatRange()로 로케일에 맞는 날짜 범위를 만들 수 있습니다.
2. formatRangeToParts()의 source 값을 구분할 수 있습니다.
3. 입력 시각, 표시 시간대, 업무상 범위 검증을 분리할 수 있습니다.

[핵심개념]

Intl.DateTimeFormat은 날짜와 시각을 로케일 규칙에 맞게 표시합니다. formatRange(start, end)는 같은 formatter 옵션을 두 경계에 적용한 뒤 CLDR의 날짜 간격 패턴으로 범위를 만듭니다. 언어별 순서·공백·기호를 처리하고 같은 연도나 월처럼 공유되는 부분을 줄입니다. 모든 필드가 같으면 하나의 날짜처럼 합쳐질 수 있습니다.

formatRangeToParts()는 type과 value 외에 source를 제공합니다. source는 startRange, endRange, shared 중 하나여서 어느 조각이 시작·종료·공통 부분인지 알려 줍니다. 별도 스타일이나 접근성 문구가 필요할 때 완성 문자열을 억지로 자르지 말고 이 정보를 사용합니다. formatRange()는 일정 계산기가 아닙니다. 종료가 시작보다 빠른지, 최대 예약 기간을 넘는지는 애플리케이션이 먼저 검사해야 합니다.

[따라하기]

아래를 date-range.js로 저장합니다.

```javascript
const formatter = new Intl.DateTimeFormat('ko-KR', {
  dateStyle: 'medium',
  timeZone: 'Asia/Seoul'
});
const start = new Date('2026-09-10T00:00:00Z');
const end = new Date('2026-09-12T00:00:00Z');

console.log(formatter.format(start));
console.log(formatter.format(end));
console.log(formatter.formatRange(start, end));
console.log([...new Set(
  formatter.formatRangeToParts(start, end).map(part => part.source)
)].join(','));
```

`node date-range.js`를 실행합니다. 예상 결과는 `2026. 9. 10.`, `2026. 9. 12.`, `2026. 9. 10. ~ 2026. 9. 12.`, `startRange,shared,endRange` 순서입니다. ISO 문자열의 Z는 UTC 시각이라는 뜻이고, 화면에서는 Asia/Seoul 기준으로 바꿉니다. Windows PowerShell·명령 프롬프트, macOS 터미널, Linux 셸에서 명령은 같습니다. Node.js의 ICU·CLDR 버전에 따라 공백과 구분 기호가 달라질 수 있습니다.

[흔한 실수]

formatter에 timeZone을 생략하면 실행 중인 컴퓨터의 기본 시간대를 써서 서버마다 날짜가 달라질 수 있습니다. `YYYY-MM-DD`만 Date에 넣고 현지 자정이라고 생각하면 UTC 해석과 시간대 변환 때문에 전날로 보일 수 있습니다. Invalid Date를 넘기면 RangeError가 날 수 있으므로 Number.isNaN(date.getTime())으로 확인하세요. 결과 문자열을 다시 파싱해 원본 날짜를 복원하려고 해도 안 됩니다.

[보안 주의]

요청에서 받은 시작·종료 값은 형식, 유효한 시각, 시작 이하 종료, 허용 가능한 최대 기간을 검사합니다. timeZone과 로케일은 서비스가 지원하는 허용 목록에서 선택합니다. 표시 문자열을 예약 충돌 판단이나 결제 기간 계산에 쓰지 말고 원본 타임스탬프로 계산하세요. 일정 소유자나 비공개 장소가 노출되지 않도록 출력 필드를 제한합니다. HTML에는 결과를 일반 텍스트로 넣습니다. 실습은 본인 소유의 로컬 일정에서만 진행합니다.

[직접 해볼 과제]

시작과 종료를 같은 날짜로 바꾸어 범위가 어떻게 줄어드는지 확인하세요. en-US와 ja-JP로 같은 범위를 표시해 순서와 기호를 비교하세요. 마지막으로 Invalid Date, 종료가 더 빠른 범위, 31일을 넘는 범위를 거부하는 validateRange 함수를 작성하세요.

[확인문제]

1. 두 날짜를 각각 format()한 뒤 직접 이어 붙이는 것보다 formatRange()가 나은 점은 무엇인가요?
2. formatRangeToParts()의 source가 shared이면 무엇을 뜻하나요?
3. formatter에 timeZone을 명시해야 하는 이유는 무엇인가요?

[다음 학습]

다음에는 Intl.DurationFormat으로 경과 시간과 작업 시간을 시·분·초 단위에 맞게 표시합니다.

[공식 참고 자료]

ECMA-402 DateTimeFormat: https://tc39.es/ecma402/#datetimeformat-objects
ECMA-402 formatRange(): https://tc39.es/ecma402/#sec-intl.datetimeformat.prototype.formatRange
ECMA-402 formatRangeToParts(): https://tc39.es/ecma402/#sec-intl.datetimeformat.prototype.formatRangeToParts
Unicode LDML 날짜 간격 형식: https://www.unicode.org/reports/tr35/tr35-dates.html#intervalFormats
Node.js 국제화 지원: https://nodejs.org/api/intl.html

댓글목록

등록된 댓글이 없습니다.

회원로그인

회원가입

사이트 정보

회사명 : 회사명 / 대표 : 대표자명
주소 : OO도 OO시 OO구 OO동 123-45
사업자 등록번호 : 123-45-67890
전화 : 02-123-4567 팩스 : 02-123-4568
통신판매업신고번호 : 제 OO구 - 123호
개인정보관리책임자 : 정보책임자명

접속자집계

오늘
4,190
어제
6,862
최대
16,772
전체
770,141
Copyright © 소유하신 도메인. All rights reserved.