[EXT-025][실무] 시간 길이를 언어에 맞게 읽기 쉽게 표시하기
페이지 정보

본문
[이번 수업]
작업 시간이나 영상 길이를 `1시간 30분 5초`처럼 표시할 때 단위 이름과 순서를 직접 붙이지 않고 JavaScript의 Intl.DurationFormat을 사용합니다. 문장형과 숫자형을 만들고 계산과 표시를 분리합니다.
[선수지식]
JavaScript 객체와 Intl의 로케일 개념을 알면 됩니다. 기간(duration)은 어떤 일이 계속된 시간의 길이이며, 달력의 특정 시작 시각이나 종료 시각과는 다릅니다.
[학습목표]
1. 기간 객체를 로케일에 맞는 문자열로 표시할 수 있습니다.
2. long과 digital 스타일의 용도를 구분할 수 있습니다.
3. 입력 검증과 기간 계산을 포맷 단계와 분리할 수 있습니다.
[핵심개념]
Intl.DurationFormat은 years부터 nanoseconds까지 시간 단위를 가진 객체를 받아 로케일 규칙에 맞게 표시합니다. `style: 'long'`은 단위 이름을 풀어 쓰고, short와 narrow는 더 짧은 형태를 사용합니다. `style: 'digital'`은 시·분·초를 시계와 비슷한 숫자 형태로 만듭니다. 기호와 공백은 ICU·CLDR 데이터와 로케일에 따라 정해지므로 문자열을 잘라 단위를 찾으면 안 됩니다.
formatToParts()는 integer, unit, literal 같은 조각과 해당 unit 정보를 돌려줍니다. 조각별 스타일이나 접근성 설명이 꼭 필요할 때만 사용하고, 보통은 format()의 완성 문자열을 그대로 출력합니다. 이 API는 단위를 자동 환산하지 않습니다. `{ minutes: 90 }`은 대개 90분으로 표시되며 1시간 30분으로 바뀌지 않습니다. 두 시각의 차이 계산, 반올림, 단위 환산은 먼저 업무 규칙에 따라 처리해야 합니다.
[따라하기]
duration.js 파일을 만들고 아래 코드를 저장합니다.
```javascript
if (typeof Intl.DurationFormat !== 'function') {
throw new Error('Intl.DurationFormat을 지원하는 런타임이 필요합니다.');
}
const duration = { hours: 1, minutes: 30, seconds: 5 };
const words = new Intl.DurationFormat('ko-KR', { style: 'long' });
const clock = new Intl.DurationFormat('ko-KR', { style: 'digital' });
console.log(words.format(duration));
console.log(clock.format(duration));
```
`node duration.js`를 실행합니다. 확인한 예상 결과는 첫 줄 `1시간 30분 5초`, 둘째 줄 `1:30:05`입니다. Windows PowerShell·명령 프롬프트, macOS 터미널, Linux 셸 모두 같은 명령을 씁니다. 런타임에 따라 공백이나 숫자 모양이 달라질 수 있으므로 뜻이 맞는지 확인합니다. 생성자가 없다는 오류가 나면 지원 여부를 확인하고 안정 버전으로 업데이트하세요.
[흔한 실수]
90분을 넣으면 자동으로 1시간 30분이 될 것이라 기대하지 마세요. `hours: 1.5`처럼 정수가 아닌 값을 넣거나 양수와 음수 단위를 섞으면 RangeError가 발생할 수 있습니다. 빈 객체는 표시할 단위가 없어 TypeError가 납니다. 기간을 날짜로 바꾸어 DateTimeFormat에 넣으면 기준일과 시간대가 끼어들어 뜻이 달라집니다. 또한 화면에 나온 문자열을 다시 읽어 원래 숫자를 복원하지 말고 원본 기간 객체를 보관하세요.
[보안 주의]
외부 입력은 JSON으로 받은 뒤 허용한 단위 키만 새 객체에 복사합니다. 각 값이 유한한 정수인지, 부호가 일관되는지, 서비스가 정한 최대 기간을 넘지 않는지 검사하세요. 과도하게 큰 값은 계산 오류와 화면 깨짐을 만들 수 있습니다. 표시 문자열을 요금이나 만료 판정에 사용하지 말고 검증된 원본 숫자로 계산합니다. 결과는 HTML 코드가 아니라 일반 텍스트로 출력합니다. 실습은 본인 소유의 로컬 데이터에서만 진행합니다.
[직접 해볼 과제]
같은 duration을 en-US와 ja-JP로 표시해 단위 이름과 순서를 비교하세요. 이어서 `{ minutes: 90 }`의 결과를 확인하고, 90분을 1시간 30분으로 나누는 normalizeMinutes 함수를 직접 작성하세요. 마지막으로 허용 키, 정수, 같은 부호, 최대 168시간을 검사하는 validateDuration 함수를 만드세요.
[확인문제]
1. Intl.DurationFormat이 기간의 단위 환산까지 자동으로 처리하지 않는 이유는 무엇인가요?
2. long 스타일과 digital 스타일은 각각 어떤 화면에 어울리나요?
3. 화면에 표시한 기간 문자열로 요금을 계산하면 안 되는 이유는 무엇인가요?
[다음 학습]
다음에는 Intl.Segmenter로 문장을 글자·단어·문장 경계에 맞게 나누고, 이모지와 한글을 안전하게 세는 방법을 배웁니다.
[공식 참고 자료]
ECMA-402 2025 DurationFormat: https://tc39.es/ecma402/2025/#durationformat-objects
ECMA-402 생성자: https://tc39.es/ecma402/2025/#sec-intl.durationformat
ECMA-402 format(): https://tc39.es/ecma402/2025/#sec-intl.durationformat.prototype.format
ECMA-402 formatToParts(): https://tc39.es/ecma402/2025/#sec-intl.durationformat.prototype.formattoparts
Unicode LDML 단위 형식: https://unicode.org/reports/tr35/tr35-general.html#Unit_Elements
Node.js 국제화 지원: https://nodejs.org/api/intl.html
작업 시간이나 영상 길이를 `1시간 30분 5초`처럼 표시할 때 단위 이름과 순서를 직접 붙이지 않고 JavaScript의 Intl.DurationFormat을 사용합니다. 문장형과 숫자형을 만들고 계산과 표시를 분리합니다.
[선수지식]
JavaScript 객체와 Intl의 로케일 개념을 알면 됩니다. 기간(duration)은 어떤 일이 계속된 시간의 길이이며, 달력의 특정 시작 시각이나 종료 시각과는 다릅니다.
[학습목표]
1. 기간 객체를 로케일에 맞는 문자열로 표시할 수 있습니다.
2. long과 digital 스타일의 용도를 구분할 수 있습니다.
3. 입력 검증과 기간 계산을 포맷 단계와 분리할 수 있습니다.
[핵심개념]
Intl.DurationFormat은 years부터 nanoseconds까지 시간 단위를 가진 객체를 받아 로케일 규칙에 맞게 표시합니다. `style: 'long'`은 단위 이름을 풀어 쓰고, short와 narrow는 더 짧은 형태를 사용합니다. `style: 'digital'`은 시·분·초를 시계와 비슷한 숫자 형태로 만듭니다. 기호와 공백은 ICU·CLDR 데이터와 로케일에 따라 정해지므로 문자열을 잘라 단위를 찾으면 안 됩니다.
formatToParts()는 integer, unit, literal 같은 조각과 해당 unit 정보를 돌려줍니다. 조각별 스타일이나 접근성 설명이 꼭 필요할 때만 사용하고, 보통은 format()의 완성 문자열을 그대로 출력합니다. 이 API는 단위를 자동 환산하지 않습니다. `{ minutes: 90 }`은 대개 90분으로 표시되며 1시간 30분으로 바뀌지 않습니다. 두 시각의 차이 계산, 반올림, 단위 환산은 먼저 업무 규칙에 따라 처리해야 합니다.
[따라하기]
duration.js 파일을 만들고 아래 코드를 저장합니다.
```javascript
if (typeof Intl.DurationFormat !== 'function') {
throw new Error('Intl.DurationFormat을 지원하는 런타임이 필요합니다.');
}
const duration = { hours: 1, minutes: 30, seconds: 5 };
const words = new Intl.DurationFormat('ko-KR', { style: 'long' });
const clock = new Intl.DurationFormat('ko-KR', { style: 'digital' });
console.log(words.format(duration));
console.log(clock.format(duration));
```
`node duration.js`를 실행합니다. 확인한 예상 결과는 첫 줄 `1시간 30분 5초`, 둘째 줄 `1:30:05`입니다. Windows PowerShell·명령 프롬프트, macOS 터미널, Linux 셸 모두 같은 명령을 씁니다. 런타임에 따라 공백이나 숫자 모양이 달라질 수 있으므로 뜻이 맞는지 확인합니다. 생성자가 없다는 오류가 나면 지원 여부를 확인하고 안정 버전으로 업데이트하세요.
[흔한 실수]
90분을 넣으면 자동으로 1시간 30분이 될 것이라 기대하지 마세요. `hours: 1.5`처럼 정수가 아닌 값을 넣거나 양수와 음수 단위를 섞으면 RangeError가 발생할 수 있습니다. 빈 객체는 표시할 단위가 없어 TypeError가 납니다. 기간을 날짜로 바꾸어 DateTimeFormat에 넣으면 기준일과 시간대가 끼어들어 뜻이 달라집니다. 또한 화면에 나온 문자열을 다시 읽어 원래 숫자를 복원하지 말고 원본 기간 객체를 보관하세요.
[보안 주의]
외부 입력은 JSON으로 받은 뒤 허용한 단위 키만 새 객체에 복사합니다. 각 값이 유한한 정수인지, 부호가 일관되는지, 서비스가 정한 최대 기간을 넘지 않는지 검사하세요. 과도하게 큰 값은 계산 오류와 화면 깨짐을 만들 수 있습니다. 표시 문자열을 요금이나 만료 판정에 사용하지 말고 검증된 원본 숫자로 계산합니다. 결과는 HTML 코드가 아니라 일반 텍스트로 출력합니다. 실습은 본인 소유의 로컬 데이터에서만 진행합니다.
[직접 해볼 과제]
같은 duration을 en-US와 ja-JP로 표시해 단위 이름과 순서를 비교하세요. 이어서 `{ minutes: 90 }`의 결과를 확인하고, 90분을 1시간 30분으로 나누는 normalizeMinutes 함수를 직접 작성하세요. 마지막으로 허용 키, 정수, 같은 부호, 최대 168시간을 검사하는 validateDuration 함수를 만드세요.
[확인문제]
1. Intl.DurationFormat이 기간의 단위 환산까지 자동으로 처리하지 않는 이유는 무엇인가요?
2. long 스타일과 digital 스타일은 각각 어떤 화면에 어울리나요?
3. 화면에 표시한 기간 문자열로 요금을 계산하면 안 되는 이유는 무엇인가요?
[다음 학습]
다음에는 Intl.Segmenter로 문장을 글자·단어·문장 경계에 맞게 나누고, 이모지와 한글을 안전하게 세는 방법을 배웁니다.
[공식 참고 자료]
ECMA-402 2025 DurationFormat: https://tc39.es/ecma402/2025/#durationformat-objects
ECMA-402 생성자: https://tc39.es/ecma402/2025/#sec-intl.durationformat
ECMA-402 format(): https://tc39.es/ecma402/2025/#sec-intl.durationformat.prototype.format
ECMA-402 formatToParts(): https://tc39.es/ecma402/2025/#sec-intl.durationformat.prototype.formattoparts
Unicode LDML 단위 형식: https://unicode.org/reports/tr35/tr35-general.html#Unit_Elements
Node.js 국제화 지원: https://nodejs.org/api/intl.html
- 이전글[EXT-026][실무] 이모지와 한글을 사용자 눈에 맞게 나누기 26.09.08
- 다음글[EXT-024][실무] 시작일과 종료일을 한 줄로 자연스럽게 표시하기 26.09.08
댓글목록
등록된 댓글이 없습니다.
