[JavaScript] Moment.js를 이용하여 Date 다루기

Do Junggeun·2020년 8월 2일
24

자바스크립트에서 날짜, 시간을 다루는 것은 항상 번거롭다. 네이티브 date 메소드는 지저분하고 API는 일관성이 부족하다. 그래서 Stackoverlow에 date와 관련된 질문을 하면 "Moment.js를 쓰세요"라는 답변을 자주 듣게 된다.

Mometn.js는 무엇인가? : What Is Moment.js?

Moment.js는 자바스크립트에서 dates를 다루기 위한 Swiss Army knife(맥가이버칼)이다. 깔끔하고 간결한 API를 이용해서 날짜와 시간을 분석, 검증, 조작, 표시할 수 있다.

이 글은 Moment.js를 시작하고 실행하는 방법과 몇 가지 일반적인 사용법을 보여준다.

Moment.js 시작하기 : Getting Started with Moment.js

Moment.js는 프로젝트의 홈페이지에서 무료로 다운로드해서 사용할 수 있다. Moment.js는 Node 애플리케이션 내에서처럼 브라우저에서도 사용할 수 있다. Node와 함께 사용하려면, 다음 명령어로 모듈을 설치하면 된다.

npm install moment

설치 후 require()하면 아래와 같이 당신의 애플리케이션에서 간편하게 사용할 수 있다.

const moment = require('moment');
const today = moment();
console.log(today.format());

// 2020-01-09T15:45:51+01:00

Moment.js를 브라우저에서 실행하려면 아래와 같이 <script>태그 내에서 사용해야한다. Moment.js는 모든 date와 time을 분석하고 조작하는 기능을 포함하는 전역(global) moment 객체를 만든다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Moment.js</title>
  </head>
  <body>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
    <script>
      // You have a 'moment' global here
      const today = moment();
      console.log(today.format());
    </script>
  </body>
</html>

Date 형식 지정 : Date Formatting

이전에는 date 문자열을 Date 객체로 변환하기 위해 개별 데이터를 추출해서 문자열을 연결해야 했다. Moment.js는 date를 어떤 형식으로든 간단하게 변환할 수 있는 기능을 제공한다. Moment를 이용한 Date 형식 변경은 아래의 예시처럼 심플하다.

moment().format('YYYY-MM-DD');

moment()를 호출하면 우리는 현재 날짜와 시각을 얻을 수 있고, format()은 이를 지정된 형식으로 변환해준다. 이 예시는 date를 하이픈(-)으로 연결되는 4자리 연도, 2자리 달, 2자리 날짜 형식으로 지정한 것이다.

팁: 공식 문서에 기재된 다양한 date 형식을 적용해보세요.

Data 검증 : Date Validation

Moment.js가 크게 단순화한 또 다른 작업은 date 검증이다. 유효성 검증을 수행하려면 원하는 date 형식과 함께 날짜 문자열을 moment 객체에 전달하고 isValid() 메서드를 호출하면 된다. date가 유효하면 true를, 유효하지 않으면 false를 반환한다.

console.log(moment("2020-01-01", "YYYY-MM-DD").isValid()); // true
console.log(moment("not-a-date", "YYYY-MM-DD").isValid()); // false

그러나 Moment는 date 형식의 일부분만 작업할 수 있는 가능성을 제공하기 때문에, 예상과 다른 결과가 반환될 수 있다는 점에 유의하라.

console.log(
  moment("2019 was a great year because I got married", "YYYY-MM-DD").isValid()
);
// 2019가 YYYY의 형식과 일치하기 때문에 true를 반환한다

이런 상황을 피하기 위해 3번째 인자로 true를 입력하여 Moment를 엄격 분석 모드(strick parsing mode)로 설정할 수 있다.

console.log(
  moment("2019 was a great year because I got married", "YYYY-MM-DD", true).isValid()
);
// false

이 기능을 보여주는 예시가 있다.

moment()가 반환하는 객체에는 다양한 flag들이 있다.

  • overflow – overflow가 발생했을 때 (13월이나 32일 등을 입력했을 때)
  • invalidMonth – month가 유효하지 않을 때 (Jannnuaarry 등)
  • empty – 입력된 date가 분석 가능한 어떤 것도 포함하지 않을 때
  • nullInput – 입력된 date가 null일 때

공식 홈페이지에서 이것들과 다른 가능한 결과들에 대해 읽어볼 수 있다.

Date 조작하기 : Manipulating Dates

moment 객체를 조작하는 다양한 옵션들이 있다. 예를 들면, days, months, years 등을 더하거나 뺄 수 있다. add()subtract() 메소드를 이용하면 된다. 아래 예시는 어떻게 7일, 7달, 7년을 더하는지 보여준다.

moment().add(7, 'days');    // 현재 날짜에 7일을 더한다
moment().add(7, 'months');  // 현재 날짜에 7개월을 더한다
moment().add(7, 'years');   // 현재 날짜에 7년을 더한다

비슷하게, subtract() 메소드는 아래와 같다.

moment().subtract(7, 'days');   // 현재 날짜에서 7일을 뺀다
moment().subtract(7, 'months'); // 현재 날짜에서 7개월을 뺀다
moment().subtract(7, 'years');  // 현재 날짜에서 7년을 뺀다

각 예시들은 moment 객체를 반환할 것임을 기억하라. 사람이 읽을 수 있는 방식의 날짜를 원한다면, 아래와 같이 형식을 지정하라.

const today = moment();
const nextWeek = today.add(7, 'days');
console.log(nextWeek.format('dddd Do MMMM, YYYY'));
// Thursday 16th January, 2020

Time From Now

다른 일반적인 작업은 두 날짜 사이의 시간을 다루는 것이다. 현재 시점으로부터의 시간 차이를 계산하기 위해, Moment.js는 fromNow() 메소드를 사용한다. 2020년 1월 1일로부터 얼마나 많은 시간이 흘렀는지 확인하는 방법은 다음과 같다:

moment('2020.01.01', 'YYYY.MM.DD').fromNow();
// 9 days ago

만약 true를 인자로 입력하면, 접미사가 없는 값을 얻는다.

moment('2020.01.01', 'YYYY.MM.DD').fromNow(true);
// 9 days

Time From Another Date

fromNow() 멧드는 현재 시점과의 비교를 위해 사용된다. 이는 두 임의의 date를 비교하는 from()의 특별한 케이스다. form()의 사용 방식은 아래에 나와있다.

const dateA = moment('01-01-1900', 'DD-MM-YYYY');
const dateB = moment('01-01-2000', 'DD-MM-YYYY');

console.log(dateA.from(dateB));

이 메소드를 아래의 데모를 통해 직접 사용해볼 수 있다.

두 날짜의 차이 계산 : Calculating the Difference Between Dates

Moment.js는 두 날짜의 차이를 계산하는 방법을 제공한다. 차이는 기본적으로 밀리초 단위로 계산되지만 일, 월, 년 등의 단위로도 반환할 수 있다. 차이를 계산하려면 diff() 메서드를 호출하면 된다. 이 방법은 날짜를 첫 번째 인자로 받는다. 시간 단위는 선택적인 두 번째 인자를 사용하여 지정할 수 있다. 두 번째 인자가 입력되지 않으면 기본값인 밀리초가 사용된다. 다음의 예와 데모는 diff()가 어떻게 사용되는지 보여준다.

const dateB = moment('2014-11-11');
const dateC = moment('2014-10-11');

console.log('Difference is ', dateB.diff(dateC), 'milliseconds');
console.log('Difference is ', dateB.diff(dateC, 'days'), 'days');
console.log('Difference is ', dateB.diff(dateC, 'months'), 'months');

Date Queries

Moment.js는 날짜를 비교하는 다양한 메소드들을 제공한다. 이 메소드들은 이름에서 의미를 알 수 있는 isBefore(), isAfter(), isSame()를 포함한다. 이들은 각각 Boolean을 결과로 반환한다. isAfter()의 사용법은 아래를 보라.

console.log(moment('2020-01-01').isAfter('2019-01-01')); // true
console.log(moment('2020-01-01').isAfter('2020-01-08')); // false

윤년을 확인하는 isLeapYear()메소드도 있다.

console.log(moment([2020]).isLeapYear()); // true
console.log(moment([2019]).isLeapYear()); // false

언어 지원 : International Language Support

Moment.js는 훌륭한 i18n 지원을 제공한다. global 언어를 할당하거나 특정한 moment 객체에 언어를 할당할 수 있다. 기본적으로 영어를 지원한다. 다른 언어를 지원하고 싶다면, 특정 언어를 moment.locale에 할당하라. Moment.js 공식 문서에서 인용한 다음의 예시는 프랑스어에 대한 지원을 어떻게 추가할 수 있는지 보여준다.

const moment = require('moment');

moment.locale('fr', {
  months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
  weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
  relativeTime : {
      future : 'dans %s',
      past : 'il y a %s',
      s : 'quelques secondes',
      m : 'une minute',
      mm : '%d minutes',
      h : 'une heure',
      hh : '%d heures',
      d : 'un jour',
      dd : '%d jours',
      M : 'un mois',
      MM : '%d mois',
      y : 'un an',
      yy : '%d ans'
  }
});

moment.locale('fr');

console.log(moment(1316116057189).fromNow());
// il y a une heure

console.log(moment().format('dddd Do MMMM, YYYY'));
// jeudi 9e janvier, 2020

Moment와 잘 맞지 않을 수 있는 이유 : Why Moment Might Not Be a Good Fit

비록 Moment.js가 훌륭한 라이브러리이지만, 다소 무겁기도 하다. 예로, 웹팩과 함께 사용하면 순수한 require('moment')만으로 모든 locales를 사용할 수 있다. 이렇게 하면 번들의 크기가 꽤 커지기 때문에 플러그인을 사용해서 다듬어야 한다.

Moment.js는 많은 훌륭한 기능이 있지만, Lodash같은 라이브러리와는 달리, 필요한 기능만 골라낼 수 없다. 항상 라이브러리 전체를 로드해야 한다.

다른 일반적인 불만은 moment 객체가 가변적이라는 것이다. 이는 개발자들에게 혼란을 야기할 수 있다. 생각해보라:

const moment = require('moment');
const today = moment();
const nextWeek = today.add(7, 'days');
console.log(today.fromNow());

콘솔에 무엇이 찍힐 것이라 예상하는가? 불행히도, 답은 "in 7 days"이다. ("a few seconds ago"가 아니다) 이는 today.add(7, 'days')가 today 객체를 7일 후로 수정했기 때문이다.

이는 moment 객체를 계산에 다루기 전에 복사하는 방식으로 피할 수 있지만, 당신이 이 사실을 기억해내기 전까지 많은 시간을 디버깅에 낭비했을 수 있다.

const moment = require('moment');
const today = moment();
const nextWeek = today.clone().add(7, 'days');
console.log(today.fromNow());
// a few seconds ago

가벼운 대안 : A Light-weight Alternative

좀 더 가벼운 대안을 찾고싶다면 date-fns를 고려해라. Date-fns는 불변적이기에, 기존의 객체를 수정하는 대신 항상 새로운 객체를 반환한다. API도 간단하고, 웹팩과 잘 어울리고, function-per-file 시스템을 통해 당신이 필요한 것만 선택할 수 있다.

자세한 내용은 다음을 참고하라: Introduction to date-fns – a Lightweight JavaScript Date Library

결론 : Conclusion

Moment.js는 시간과 날짜를 다루고 검증하는데 정말 좋은 라이브러리다. 이 글에서 우리는 브라우저와 Node에서 시간과 날짜를 분석, 검증, 조작하는 여러 방법에 집중했다. Moment.js에 여러 유용한 플러그인들도 사용할 수 있다. ISO Calendar, Jalaali Calendar를 비롯하여 공식 플러그인 페이지에서 다양한 플러그인 찾을 수 있다. Moment.js에 대해 더 알고싶다면 라이브러리의 공식 문서를 읽어보라.

0개의 댓글