자바스크립트의 Temporal API를 사용하여 정확하고 직관적인 시간 간격 계산을 하는 종합 가이드입니다. 기본적인 기간 생성부터 고급 연산 및 서식 지정까지 모든 것을 다룹니다.
자바스크립트 Temporal Duration: 시간 간격 계산 마스터하기
자바스크립트의 Temporal API는 날짜, 시간, 시간 간격을 다루는 현대적이고 강력한 방법을 소개합니다. Temporal.Duration
객체는 시간의 길이를 나타내며, 시간 간격 계산을 수행하는 명확하고 직관적인 접근 방식을 제공합니다. 이 글에서는 Temporal.Duration
의 세부 사항을 깊이 파고들어 다양한 사용 사례에 맞게 기간을 생성, 조작, 서식 지정하는 방법을 보여줍니다.
Temporal.Duration이란 무엇인가?
Temporal.Duration
은 시간의 범위를 나타내며, 년, 월, 일, 시간, 분, 초 및 초의 분수(밀리초, 마이크로초, 나노초) 단위로 표현합니다. 특정 시점을 나타내는 Date
객체와 달리, Temporal.Duration
은 시간의 양을 나타냅니다. 이는 ISO 8601 기간 형식(예: P1Y2M10DT2H30M
은 1년 2개월 10일 2시간 30분을 나타냄)을 따릅니다. Temporal API는 기존의 Date
객체보다 더 직관적이고 오류 발생 가능성이 적도록 설계되었습니다.
Temporal.Duration 객체 생성하기
Temporal.Duration
객체를 생성하는 방법에는 여러 가지가 있습니다:
1. 일반 객체로부터 생성
원하는 속성을 가진 객체를 전달하여 기간을 생성할 수 있습니다:
const duration = new Temporal.Duration(1, 2, 10, 2, 30, 0, 0, 0);
console.log(duration.toString()); // 출력: P1Y2M10DT2H30M
이는 1년, 2개월, 10일, 2시간, 30분의 기간을 생성합니다. 인수는 years
, months
, weeks
, days
, hours
, minutes
, seconds
, milliseconds
, microseconds
, nanoseconds
순서에 해당합니다.
2. ISO 8601 문자열로부터 생성
Temporal.Duration.from()
을 사용하여 ISO 8601 기간 문자열로부터 기간을 생성할 수도 있습니다:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
console.log(duration.toString()); // 출력: P1Y2M10DT2H30M
이는 문자열 형식으로 저장되거나 외부 소스로부터 받은 기간을 다룰 때 특히 유용합니다.
3. Temporal.Instant
, Temporal.ZonedDateTime
등과 함께 add()
및 subtract()
메서드 사용
다른 Temporal 타입(예: Temporal.Instant
또는 Temporal.ZonedDateTime
)에서 Temporal.Duration
을 더하거나 뺀 후, 두 시점을 빼면 그 차이를 나타내는 Temporal.Duration
이 반환됩니다. 예를 들어:
const now = Temporal.Now.zonedDateTimeISO();
const later = now.add({ hours: 5 });
const duration = later.since(now);
console.log(duration.toString()); // 출력: PT5H
기간 구성 요소에 접근하기
Temporal.Duration
객체의 속성을 사용하여 개별 구성 요소에 접근할 수 있습니다:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
console.log(duration.years); // 출력: 1
console.log(duration.months); // 출력: 2
console.log(duration.days); // 출력: 10
console.log(duration.hours); // 출력: 2
console.log(duration.minutes); // 출력: 30
console.log(duration.seconds); // 출력: 0
console.log(duration.milliseconds); // 출력: 0
console.log(duration.microseconds); // 출력: 0
console.log(duration.nanoseconds); // 출력: 0
기간으로 산술 연산 수행하기
Temporal.Duration
객체는 add()
및 subtract()
메서드를 사용하여 덧셈과 뺄셈을 지원합니다. 이 메서드들은 연산 결과를 나타내는 새로운 Temporal.Duration
객체를 반환합니다.
const duration1 = Temporal.Duration.from("P1Y2M");
const duration2 = Temporal.Duration.from("P3M4D");
const addedDuration = duration1.add(duration2);
console.log(addedDuration.toString()); // 출력: P1Y5M4D
const subtractedDuration = duration1.subtract(duration2);
console.log(subtractedDuration.toString()); // 출력: P10M26D
더 복잡한 계산을 위해 이 메서드들을 연쇄적으로 사용할 수도 있습니다:
const duration = Temporal.Duration.from("P1D").add({ hours: 12 }).subtract({ minutes: 30 });
console.log(duration.toString()); // 출력: P1DT11H30M
negated()
메서드는 모든 구성 요소가 부정된 새로운 Temporal.Duration
객체를 반환합니다:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const negatedDuration = duration.negated();
console.log(negatedDuration.toString()); // 출력: -P1Y2M10DT2H30M
abs()
메서드는 모든 구성 요소가 양수 값(절대값)인 새로운 Temporal.Duration
객체를 반환합니다:
const duration = Temporal.Duration.from("-P1Y2M10DT2H30M");
const absoluteDuration = duration.abs();
console.log(absoluteDuration.toString()); // 출력: P1Y2M10DT2H30M
with()
메서드를 사용하면 일부 또는 모든 속성을 새 값으로 변경한 새로운 Temporal.Duration
인스턴스를 만들 수 있습니다. 인수 객체에 값이 지정되지 않은 경우, 기간의 원래 값이 사용됩니다. 예를 들어:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const newDuration = duration.with({ years: 2, days: 5 });
console.log(newDuration.toString()); // 출력: P2Y2M5DT2H30M
기간 정규화하기
기간은 때때로 정규화되지 않은 형태로 표현될 수 있습니다(예: P1Y12M
은 P2Y
로 단순화될 수 있음). normalized()
메서드는 기간을 가장 간결한 형태로 단순화하려고 시도합니다. 그러나 다양한 월 길이에 따른 복잡성을 처리하기 위해 기준 날짜가 필요합니다. 제대로 정규화하려면 Temporal.PlainDate
, Temporal.ZonedDateTime
또는 Temporal.Instant
인스턴스가 필요합니다.
예를 들어, 월과 일이 포함된 기간을 정규화하려면 기준 날짜가 필요합니다:
const duration = Temporal.Duration.from("P1M32D");
const referenceDate = Temporal.PlainDate.from("2024-01-01");
const normalizedDuration = duration.normalized({ relativeTo: referenceDate });
console.log(normalizedDuration.toString()); // 출력: P2M1D
이 예에서, 기간 P1M32D
는 2024년 1월 1일을 기준으로 정규화되어 P2M1D
가 됩니다. 왜냐하면 1월은 31일이기 때문입니다.
시간 구성 요소(시간, 분, 초 등)만 다루는 경우, 기준 날짜 없이 정규화할 수 있습니다:
const duration = Temporal.Duration.from("PT25H61M");
const normalizedDuration = duration.normalized({ relativeTo: null }); //또는 relativeTo 인수를 생략
console.log(normalizedDuration.toString()); // 출력: P1DT2H1M
기간 비교하기
compare()
메서드를 사용하여 기간을 비교할 수 있습니다. 이 메서드는 다음을 반환합니다:
- -1: 첫 번째 기간이 두 번째 기간보다 짧은 경우.
- 0: 기간이 동일한 경우.
- 1: 첫 번째 기간이 두 번째 기간보다 긴 경우.
const duration1 = Temporal.Duration.from("P1Y");
const duration2 = Temporal.Duration.from("P6M");
const comparisonResult = Temporal.Duration.compare(duration1, duration2);
console.log(comparisonResult); // 출력: 1
실용적인 예제
1. 이벤트까지 남은 시간 계산하기
특정 이벤트까지 남은 시간을 계산하고 싶다고 가정해 봅시다. Temporal.Now.zonedDateTimeISO()
를 사용하여 현재 시간을 얻고, 이벤트 날짜를 뺍니다. 이벤트 날짜가 지났다면 출력은 음수가 됩니다.
const eventDate = Temporal.ZonedDateTime.from({ timeZone: 'America/Los_Angeles', year: 2024, month: 12, day: 25, hour: 9, minute: 0, second: 0 });
const now = Temporal.Now.zonedDateTimeISO('America/Los_Angeles');
const durationUntilEvent = eventDate.since(now);
console.log(durationUntilEvent.toString()); // 출력 예: P262DT14H30M (현재 날짜와 시간에 따라 다름)
2. 프로젝트 작업 기간 추적하기
프로젝트 관리에서 Temporal.Duration
을 사용하여 작업의 예상 또는 실제 기간을 추적할 수 있습니다.
const task1EstimatedDuration = Temporal.Duration.from("PT8H"); // 8시간
const task2EstimatedDuration = Temporal.Duration.from("PT16H"); // 16시간
const totalEstimatedDuration = task1EstimatedDuration.add(task2EstimatedDuration);
console.log(`총 예상 기간: ${totalEstimatedDuration.toString()}`); // 출력: 총 예상 기간: P1DT
3. 나이 계산하기
나이를 정확하게 계산하려면 윤년과 시간대를 고려해야 하지만, Temporal.Duration
은 합리적인 추정치를 제공할 수 있습니다:
const birthDate = Temporal.PlainDate.from("1990-05-15");
const currentDate = Temporal.PlainDate.from("2024-01-20");
const ageDuration = currentDate.since(birthDate, { smallestUnit: 'years' });
console.log(`추정 나이: ${ageDuration.years}세`); // 출력: 추정 나이: 33세
4. 사람이 읽기 쉬운 형식으로 기간 표시하기
종종 기간을 사람이 읽기 쉬운 형식으로 표시해야 합니다. Temporal.Duration
에는 내장된 서식 지정 기능이 없지만, 사용자 정의 서식 로직을 만들 수 있습니다:
function formatDuration(duration) {
const parts = [];
if (duration.years) parts.push(`${duration.years}년`);
if (duration.months) parts.push(`${duration.months}개월`);
if (duration.days) parts.push(`${duration.days}일`);
if (duration.hours) parts.push(`${duration.hours}시간`);
if (duration.minutes) parts.push(`${duration.minutes}분`);
if (duration.seconds) parts.push(`${duration.seconds}초`);
return parts.join(', ');
}
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const formattedDuration = formatDuration(duration);
console.log(formattedDuration); // 출력: 1년, 2개월, 10일, 2시간, 30분
고급 사용법 및 고려사항
1. 시간대 처리
시간대 경계나 일광 절약 시간제 전환을 가로지르는 시간 간격을 다룰 때는 정확한 계산을 보장하기 위해 Temporal.ZonedDateTime
을 사용하는 것이 중요합니다. Temporal.PlainDate
와 Temporal.PlainTime
을 사용하면 시간대 변환을 피할 수 있습니다.
2. 최소 단위 및 반올림
since()
및 until()
메서드는 종종 결과 기간의 최소 단위를 정의하는 옵션을 받습니다. 예를 들어, 이벤트까지의 시간을 계산하고 결과를 일 단위로 제한할 수 있습니다.
const eventDate = Temporal.PlainDate.from("2024-12-25");
const now = Temporal.PlainDate.from("2024-01-20");
const durationUntilEvent = now.until(eventDate, { smallestUnit: 'days' });
console.log(durationUntilEvent.toString()); // 출력 예: PT340D
3. 윤초
Temporal은 기본적으로 윤초를 고려하지 않습니다. 극도의 정밀도가 필요한 경우, 윤초를 별도로 처리해야 합니다.
4. IANA 시간대
Temporal API는 IANA(Internet Assigned Numbers Authority) 시간대 데이터베이스에 의존합니다. 시간대 변환을 정확하게 처리하려면 환경에 최신 버전의 IANA 데이터베이스가 있는지 확인해야 합니다.
모범 사례
- 기간 문자열에 ISO 8601 형식 사용: 이는 일관성과 상호 운용성을 보장합니다.
- 적절한 Temporal 타입 선택: 시간대 지원 여부에 따라
Temporal.PlainDate
,Temporal.PlainTime
,Temporal.ZonedDateTime
또는Temporal.Instant
를 사용합니다. - 필요 시 기간 정규화: 정규화는 기간을 단순화하고 비교하기 쉽게 만듭니다.
- 시간대를 신중하게 처리: 시간대 변환은 복잡할 수 있으므로
Temporal.ZonedDateTime
을 사용하고 일광 절약 시간제 전환에 유의해야 합니다. - 최소 단위 고려: 기간을 계산할 때 원하는 수준의 정밀도를 얻기 위해 최소 단위를 지정합니다.
- 단위 테스트 작성: 기간 계산이 정확한지 확인하기 위해 코드를 철저히 테스트합니다.
흔히 발생하는 문제점
- 시간대 무시: 시간대를 고려하지 않으면 특히 다른 위치의 이벤트를 다룰 때 부정확한 기간 계산으로 이어질 수 있습니다.
- 기존 Date 객체 사용: 기존
Date
객체는 특이한 동작과 불일치로 알려져 있습니다. 더 신뢰할 수 있는 날짜 및 시간 처리를 위해 Temporal API를 선호해야 합니다. - 기간을 정규화하지 않음: 기간을 정규화하지 않으면 비교 및 계산이 더 복잡해질 수 있습니다.
- 잘못된 ISO 8601 형식: 유효하지 않은 ISO 8601 기간 문자열을 사용하면 오류가 발생할 수 있습니다.
다양한 문화권에서의 실제 사용 사례
Temporal API는 시간대 차이와 문화적 뉘앙스가 중요한 글로벌 애플리케이션에서 특히 유용할 수 있습니다. 다음은 몇 가지 예입니다:
- 글로벌 이벤트 일정 관리: 일광 절약 시간제 전환을 고려하여 여러 시간대에 걸쳐 이벤트를 정확하게 예약합니다. 예를 들어, PST 오전 9시에 시작하는 웨비나를 예약하고 CET, JST, AEDT와 같은 다양한 시간대에서 해당 시작 시간을 표시합니다.
- 국제 여행 계획: 경유 및 시간대 변경을 포함한 여행 기간을 계산합니다. 이는 여정을 생성하고 항공편 일정을 관리하는 데 유용합니다. 예를 들어, 뉴욕에서 도쿄까지의 총 이동 시간을 계산하며, 런던에서의 경유와 시간대 차이를 조정합니다.
- 글로벌 전자상거래: 사용자의 현지 시간대로 예상 배송 시간을 표시합니다. 이를 위해서는 출발지 시간대, 배송 기간 및 목적지 시간대를 고려해야 합니다. 예를 들어, 독일 창고에서 호주 고객에게 배송되는 상품의 예상 배송 시간을 7일로 하여 고객의 현지 시간으로 표시합니다.
- 국경 간 금융 거래: 여러 지역에 걸쳐 이자 발생 또는 지불 기한을 정확하게 계산합니다. 이는 종종 각국의 다른 영업일과 공휴일을 고려해야 합니다. 예를 들어, 싱가포르의 공휴일을 고려하여 싱가포르 대출에 대한 이자를 계산합니다.
- 다문화 캘린더 애플리케이션: 이슬람 또는 히브리력과 같은 다양한 달력 시스템을 지원하고 이러한 달력을 기반으로 이벤트 기간 및 알림을 정확하게 계산합니다.
- 글로벌 프로젝트 관리: 분산된 팀에 걸쳐 프로젝트 작업 기간 및 마감일을 추적하며, 다른 근무 일정과 시간대를 고려합니다.
결론
Temporal.Duration
은 자바스크립트에서 시간 간격을 다루는 견고하고 직관적인 방법을 제공합니다. 그 기능과 모범 사례를 이해함으로써 애플리케이션에서 정확하고 신뢰할 수 있는 기간 계산을 자신 있게 수행할 수 있습니다. Temporal API를 채택하면 더 깨끗하고 유지 관리하기 쉬운 코드를 작성할 수 있으며, 기존의 날짜 및 시간 처리와 관련된 오류 위험을 줄일 수 있습니다.
Temporal API를 더 깊이 파고들면서, 그 기능을 완전히 파악하기 위해 공식 문서를 참조하고 다양한 시나리오로 실험해 보는 것을 잊지 마십시오. 현대적인 디자인과 포괄적인 기능을 갖춘 Temporal은 우리가 자바스크립트에서 날짜, 시간, 기간을 다루는 방식을 혁신할 것입니다.