한국어

자바스크립트의 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

기간 정규화하기

기간은 때때로 정규화되지 않은 형태로 표현될 수 있습니다(예: P1Y12MP2Y로 단순화될 수 있음). 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() 메서드를 사용하여 기간을 비교할 수 있습니다. 이 메서드는 다음을 반환합니다:

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.PlainDateTemporal.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 데이터베이스가 있는지 확인해야 합니다.

모범 사례

흔히 발생하는 문제점

다양한 문화권에서의 실제 사용 사례

Temporal API는 시간대 차이와 문화적 뉘앙스가 중요한 글로벌 애플리케이션에서 특히 유용할 수 있습니다. 다음은 몇 가지 예입니다:

결론

Temporal.Duration은 자바스크립트에서 시간 간격을 다루는 견고하고 직관적인 방법을 제공합니다. 그 기능과 모범 사례를 이해함으로써 애플리케이션에서 정확하고 신뢰할 수 있는 기간 계산을 자신 있게 수행할 수 있습니다. Temporal API를 채택하면 더 깨끗하고 유지 관리하기 쉬운 코드를 작성할 수 있으며, 기존의 날짜 및 시간 처리와 관련된 오류 위험을 줄일 수 있습니다.

Temporal API를 더 깊이 파고들면서, 그 기능을 완전히 파악하기 위해 공식 문서를 참조하고 다양한 시나리오로 실험해 보는 것을 잊지 마십시오. 현대적인 디자인과 포괄적인 기능을 갖춘 Temporal은 우리가 자바스크립트에서 날짜, 시간, 기간을 다루는 방식을 혁신할 것입니다.