JavaScript Date API: 분석 및 대안 탐구

김현조·2023년 3월 12일
4

FrontEnd

목록 보기
3/9
post-thumbnail

Date API

개념

JavaScript의 Date는 JavaScript 날짜의 기반은 1970년 1월 1일 UTC 자정과의 시간 차이를 밀리초 단위로 나타낸다.

let today = new Date();
let birthday = new Date('December 17, 1995 03:24:00');
let birthday = new Date('1995-12-17T03:24:00');
let birthday = new Date(1995, 11, 17);            // 월은 0부터 시작
let birthday = new Date(1995, 11, 17, 3, 24, 0);

하지만 많은 javascript 개발자들은 Date API 대신 다른 라이브러리 등을 채택하여 사용한다. 어떤 문제점이 있기에 기본 스펙 대신 라이브러리를 사용하는 것이 자연스러워졌을까?

문제점

“날짜”만 사용할 수 없음

Date 객체를 이용하면 시간까지 포함된 datetime이 생성되어, 날짜만 사용하고 싶어도 사용할 수 없도록 구현되어 있다.

let date = new Date(2011, 1, 22);
// Tue Feb 22 2011 00:00:00 GMT+0000 (Greenwich Mean Time)

웹 호환성 문제

new Date호출 시에 실행되는 Date.parse함수가 브라우저나 버전마다 구현이 다르다. 어떤 브라우저는 UTC기준, 또 어떤 브라우저는 해당 브라우저가 속한 Timezone 기준으로 해석하여 문제가 발생할 수 있다.

UTC가 default임

DateString으로 date 객체 생성시 UTC 기준으로 date가 생성되어 오차 발생 가능성이 있다. 아래의 경우 단순히 Date.parse 함수를 호출하여 timestamp를 생성한 것으로 보인다. 그러나 timezone에 따라 문제가 발생할 수 있다.

let myDate = Date.parse('01 Jan 1999');
  • UTC의 경우 915148800000
  • UTC+3:00의 경우 915138000000
  • UTC-5:00의 경우 915166800000

마지막 경우에 JavaScript는 Unix timestamp에서 5시간을 뺀다. 앞서 언급된 JavaScript는 date 단독으로는 사용할 수 없다는 사실에 따라 1st Jan 1999가 아니라 31st Dec 1998라는 당황스러운 결과를 얻게 된다.

월은 0을 기준으로 생성

만약 2011년 2월 22일에 대한 date를 생성하고 싶다면 아래와 같이 작성하면 될 것이라 예상된다.

let date = new Date(2011, 2, 22);

사실은 아니다! JavaScript의 월은 일, 연과 다르게 0부터 시작되어 아래와 같이 두번째 인자에 “1”을 작성해야 한다. 어렵진 않아도 헷갈린다.

let date = new Date(2011, 1, 22);

이렇게 다양한 문제를 안고 있는 Date 객체를 그대로 사용하는 것이 가장 좋은 방법이라고 하기엔 무리가 있어보인다. 그렇다면 어떤 대안들이 있을까?

대안

Moment.js

JavaScript 날짜 관련 라이브러리 중 가장 많이 사용된다. 현재는 더 이상의 업데이트가 없을 것이라 공지 되었으나, 여전히 많이 채택되고 있다.

날짜 관련 코드 중에 굉장히 자주 사용되는 “몇분전”, “몇년전”을 나타내는 코드를 Vanilla JS로 작성한다면 다음과 같을 것이다.

function timeForToday(value: string) {
  const today = new Date();
  const timeValue = new Date(value);

  const betweenTime = Math.floor((today.getTime() - timeValue.getTime()) / 1000 / 60);
  if (betweenTime < 1) return '방금전';
  if (betweenTime < 60) {
    return `${betweenTime}분전`;
  }

  const betweenTimeHour = Math.floor(betweenTime / 60);
  if (betweenTimeHour < 24) {
    return `${betweenTimeHour}시간전`;
  }

  const betweenTimeDay = Math.floor(betweenTime / 60 / 24);
  if (betweenTimeDay < 365) {
    return `${betweenTimeDay}일전`;
  }

  return `${Math.floor(betweenTimeDay / 365)}년전`;
}

그러나 momentjs를 이용한다면 내장 함수로 간단하게 작성할 수 있다.

import moment from 'moment';
import 'moment/dist/locale/ko';

export function timeForToday(createdAt: string) {
  return moment(createdAt).locale('ko').fromNow();
}

기존의 JavaScript 객체가 가진 문제점들을 모두 해결하면서, 편리한 기능도 장착하고 있으니 고려해볼만한 선택지이다.

Temporal API

JavaScript 진영에서도 현대적인 date API를 준비하고 있다. 현재 stage 3 proposal 단계로 실험적으로 운영되고 있으나 곧 표준에 포함될 것이라 예상된다.

  • 사용하기 편리한 날짜, 시간 연산 지원
  • 모든 시간대 지원
  • 시간, 날짜 문자열 파싱 문제 해결
  • 그레고리력이 아닌 달력도 지원

아래와 같이 사용 가능하다.

// 현재 시간대
Temporal.Now.timeZone(); // Temporal.TimeZone 객체를 반환
Temporal.Now.timeZone().id; // "Asia/Seoul"

// 현재 시간에 대한 Unix timestamp
Temporal.Now.instant().epochSeconds;
Temporal.Now.instant().epochMilliseconds;

// 시간 단독
new Temporal.PlainTime(11, 22, 33);
Temporal.PlainTime.from('11:22:33');

// 날짜 단독
new Temporal.PlainDate(1996, 2, 21);
Temporal.PlainDate.from('1996-2-21');

// 시간, 날짜
new Temporal.PlainDateTime(1996, 2, 21, 15, 30, 50);
Temporal.PlainDateTime.from('1996-02-21T15:30:50');

JavaScript의 Date API가 가진 문제점들을 대부분 해결하면서도 외부 라이브러리를 가져와 번들 사이즈를 늘릴 이유가 없으니 미리 공부하거나 polyfill을 이용하여 개발하며 표준 스펙에 들어가기를 기다려보는 것도 좋은 선택이 될 것 같다.

ETC

Moment.js가 업데이트를 하지 않으면서 공식 문서에서 아래를 포함한 몇개의 대안을 제시해주었다. 해당 문서 내용에서 대안책을 찾아보는 것도 방법이 될 수 있다.

출처

6개의 댓글

comment-user-thumbnail
2023년 3월 12일

굿 ~ 👍

1개의 답글
comment-user-thumbnail
2023년 4월 19일

잘 보고 갑니다~

1개의 답글