본문 바로가기

[Project] 프로젝트 삽질기45 (feat Date)

어가며

날짜와 관련해서 아리송한 것들이 많았습니다. DB의 createdAt 컬럼 데이터를 조회했을 때 '2023-02-13T11:57:33:05.442Z' 라고 출력된다면 여기서 Z는 무엇인지, UTC는 무엇인지 정확하게 알지 못했습니다. 심지어 Javascript의 Date는 불변이 아니라는 이야기를 종종 들었는데, 불변이 아닌 게 어떤 문제가 있는 건지 알 수 없었습니다. 이번 기회에 Date에 대해 정리해 봐야겠다고 생각했습니다. 이 글은 Date에 대해 공부하며 작성됐습니다. 

 

 

 

 


 

Date

자바스크립트로 알고리즘을 공부하다 보면, Date Type을 활용하는 문제가 꼭 한 문제씩 나옵니다. 문제를 풀기 위해 Date 객체 중에서 이런저런 메서드를 잘 조합하다 보면 원하는 데이터를 얻을 수 있는데, 그때마다 참 사용하기 어렵고 불편하다는 생각을 여러 번 했습니다. 개인적으로 Date 객체를 사용하면서 어려움을 겪었던 것들을 적어보자면 아래와 같습니다. 

 

 

 

 

 

1. 살펴보기 힘든 인터페이스

Date 객체는 프로젝트 개발을 하면서도 사용해야 했는데, 이 때도 불편함들이 있었습니다. 예를 들어 어제의 날짜 및 시간을 구해야 한다면 아래와 같이 구할 수 있을 것입니다.

 

const now = new Date();	// 현재 날짜 및 시간
console.log("현재 : ", now); // 2023-02-14T10:18:53.651Z
const yesterday = new Date(now.setDate(now.getDate() - 1));	// 어제
console.log("어제 : ", yesterday); // 2023-02-13T10:18:53.651Z

 

위의 코드를 보면, '어제'라는 날짜를 구할 때 복잡하게 날짜를 구하는 것을 볼 수 있습니다. 먼저 현재 시간에서 getDate() 메서드를 활용해서 주어진 날짜의 현지 시간 기준 일을 구하고, 일자 데이터를 setDate에 전달함으로써 현재 설정된 월의 시작 부분을 기준으로 Date 객체의 날짜를 설정합니다. '어제' 날짜를 구하기 위해서는 단 번에 이해하기 어려운 긴 코드를 작성해야 하는 불편함이 있습니다. 

 

 

 

 

 

2. 현지 시간이 아닌 Z가 출력됨

심지어 Date 객체를 사용해서 시간 데이터를 출력해 보면, 시간 데이터에 알 수 없는 문자인 Z가 같이 나오기도 합니다. 

 

2023-02-14T10:18:53.651Z
2023-02-13T10:18:53.651Z

console.log(Intl.DateTimeFormat().resolvedOptions().timeZone); // Asia/Seoul

 

기본적으로 Date는 생성되고서 UTC 기준으로 시간을 생성합니다. 현재 Asia/Seoul localtime존으로 설정되어 있기에 한국을 기준으로 new Date()을 입력하면 -9시간이 된 GMT 00:00 기준으로 시간을 생성해 줍니다. 여기서 Z는 무엇인지, 배경지식이 없다면 이해하기 어렵기만 합니다. 

 

 

 

 

 

 

3. Not Immutable (불변 객체가 아니다)

심지어 Date 객체는 불변하지 않다는 문제가 있었습니다. 아래의 예시를 살펴보겠습니다.

 

 

 

class Person {
  constructor(private birth: Date) {}

  public getBirth(): Date {
    return this.birth;
  }
}

class test {
  public static dateFuc() {
    const data = new Date();

    const kim: Person = new Person(data);
    const birth = kim.getBirth();

    console.log(birth); // 2023-02-13T15:02:11.783Z
    data.setDate(40);
    console.log(birth); // 2023-03-11T15:02:11.783Z
  }
}

const realTest = test.dateFuc();

 

 

 

위의 예시를 보면, kim의 값으로 new Person의 인스턴스를 할당했습니다. 인스턴스에는 Date 객체가 파라미터로 전달됐습니다. Person 인스턴스를 생성한 후, getBirth 메서드를 호출함으로써 날짜 값을 birth에 할당했습니다.

 

birth 값을 로그로 출력하고, data.setDate(40)로 Date 객체를 수정한 후 다시 birth 값을 로그로 출력하면 값이 다르게 나오는 것을 볼 수 있습니다.

 

불변 객체라면 날짜를 40으로 수정하더라도 kim의 birth 값은 변경되어서는 안 됩니다. 

 

 

 

 

class Person {
  constructor(private readonly birth: Date) {}

  public getBirth(): Date {
    return new Date(this.birth.getTime());
  }
}

class test {
  public static dateFuc() {
    const data = new Date();

    const kim: Person = new Person(data);

    const birth = kim.getBirth();

    console.log(birth); // 2023-02-13T15:02:11.783Z
    data.setDate(40);
    console.log(birth); // 2023-02-13T15:02:11.783Z
  }
}

const realTest = test.dateFuc();

 

만약 위에서 겪은 문제를 해결하기 위해서는, getBirth() 메서드로 birth를 리턴할 때, 새로운 객체를 생성해서 리턴하면 됩니다. 이렇게 한다면 다른 개발자가 객체를 수정하더라도 kim의 Date에는 영향을 주지 않을 수 있습니다. 

 

 

 

 

 

 

이렇게 JS의 Date 객체를 사용하다 보면 이해하기 어려운 점도 있을 수 있고, 다양한 어려움 또한 겪을 수 있습니다. (만약 Date에 대해 자세히 이해하고 싶으신 분들은 아래 링크를 참고해 주시면 됩니다.) 이런 점들 때문인지, JS에서 Date 타입을 더 잘 활용할 수 있도록 돕는 라이브러리들이 있습니다.

 

 

 

 

https://d2.naver.com/helloworld/645609

 

왜 내가 작성한 JavaScript Date 코드가 서버에서는 다르게 보이는 거죠? - 재그지그의 개발 블로그

JavaScript에서 흔히 혼동되는 Date 객체에 대한 개념을 정리해봅니다.

wormwlrm.github.io

 

 

 

 

 

 


Date 라이브러리

여러 라이브러리 중 어떤 라이브러리를 활용해야 하나 고민됐습니다. moment는 불변하지 않기도 하고, 느리고 무겁다는 평이 많았고 심지어 deprecated 되었습니다. 만약 사이즈가 중요하다면 date-fns 혹은 day.js를 사용하는 것이 좋아 보이지만, 백엔드에서는 번들링에 대한 걱정이 없어서, 사이즈 걱정은 없었습니다.  

 

 

 

 

출처: https://inventi.studio/en/blog/why-you-shouldnt-use-moment-js#fnref2

 

 

 

 

라이브러리를 비교하면서, 불변이 보장됐고, 변경 실패 시 Error를 보장하며, 타임존을 지원하는 luxon과 js-joda 중 하나를 사용하면 좋겠다고 생각했습니다. 둘 중에서는 js-joda가 luxon보다 속도 측면에서 우위에 있다고 판단하여 js-joda를 활용하기로 결정했습니다(지금은 js-joda는 deprecated가 됐기에, @js-joda/core를 활용해야 합니다). 

 

 

 

const LocalDate = require('@js-joda/core').LocalDate;

const d = LocalDate.parse('2012-12-24').atStartOfDay().plusMonths(2); 
// 2013-02-24T00:00:00

 

 

공식 문서에 나와 있는 사용법을 보면, 코드만 봐도 어떤 데이터가 출력될지 직관적으로 보이고, 불변을 보장하기 때문에 기존 Date 객체를 활용하는 것보다 더 유용하게 날짜, 시간 데이터를 활용할 수 있습니다. 

 

 

만약 TypeORM에서 js-joda를 활용하고자 하는 분들은 아래 링크를 참고하시면 도움이 될 듯싶습니다. 

 

 

 

js-joda 로 TypeORM Date 타입 대체하기 (with NestJS)

JavaScript 의 Date Type은 JavaScript의 단점을 이야기할때 항상 거론되는 점인데요. javascript-date-type-is-horribly-broken 위 글에서 언급한 연산에 관한 문제도 있지만, 단순히 +1 Day를 해야하는데도 아래와 같

jojoldu.tistory.com

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

 

마치며

공부를 하며 그동안 아주 기초적인 것들을 제대로 공부하지 않았다는 것을 깨닫습니다. 좋은 기술을 배우는 것도 좋지만, 기술의 기반이 되는 기초적인 지식을 먼저 쌓는 것이 중요하다는 것을 다시금 깨달았습니다. 기초가 튼튼한 개발자가 되고 싶습니다.

 

 

 

 

 

 

 


 

 

 

 

출처

 

 

왜 내가 작성한 JavaScript Date 코드가 서버에서는 다르게 보이는 거죠? - 재그지그의 개발 블로그

JavaScript에서 흔히 혼동되는 Date 객체에 대한 개념을 정리해봅니다.

wormwlrm.github.io

 

나를 괴롭히던 Date 정리

Date때문에 얼마나 삽질을 많이했는지 모른다. 단순히 출력할때야 dayjs 나 momentjs 로 간단히 해결하지만 node 서버에서 db와 연동할때, UTC 타임존 때문에 처음엔 너무 해깔렸고, 특히나 스케줄링 서

nyagm.tistory.com

 

js-joda 로 TypeORM Date 타입 대체하기 (with NestJS)

JavaScript 의 Date Type은 JavaScript의 단점을 이야기할때 항상 거론되는 점인데요. javascript-date-type-is-horribly-broken 위 글에서 언급한 연산에 관한 문제도 있지만, 단순히 +1 Day를 해야하는데도 아래와 같

jojoldu.tistory.com

 

Home

yceffort

yceffort.kr

 

Why you shouldn't use Moment.js...

...or, at least, what you should remember while using it. The most popular JS DateTime library that gave us everything we wanted so much from native Date API. If it is much better than native API, why do we advise you not to use it?

inventi.studio

 

[Node.js] Date 라이브러리 비교

- Date 라이브러리 (Moment.js 의 대체) 프로그래밍을 하다보면 날짜와 관련된 로직을 구현, 처리하는 일이 굉장히 많습니다. 이때 Node.js 에서는 폭넓게 사용되던 라이브러리가 Moment.js 입니다. 하지

grepper.tistory.com

 

[Node.js] Date 라이브러리 퍼포먼스 비교

- Do What? 지난번 글에서 Moment.js 의 대체 Date 라이브러리인 Luxon, Day.js, date-fns, js-Joda 4가지 라이브러리의 사용법과 관련 함수들에 대해 봤었습니다. 이번엔 이어서 퍼포먼스와 기타 지표를 비교하

grepper.tistory.com

 

 

람보르기니와 지프랭글러

슈퍼카의 대명사인 람보르기니는 오프로더의 대명사인 지프랭글러 보다 더 빠른 자동차일까? 이 질문에 대해 당연하게 답을 내리는 사람이 있고, 답을 할 수 없는 사람도 있다. 이 주제에 대해

jojoldu.tistory.com