들어가며
날짜와 관련해서 아리송한 것들이 많았습니다. 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
Date 라이브러리
여러 라이브러리 중 어떤 라이브러리를 활용해야 하나 고민됐습니다. moment는 불변하지 않기도 하고, 느리고 무겁다는 평이 많았고 심지어 deprecated 되었습니다. 만약 사이즈가 중요하다면 date-fns 혹은 day.js를 사용하는 것이 좋아 보이지만, 백엔드에서는 번들링에 대한 걱정이 없어서, 사이즈 걱정은 없었습니다.
라이브러리를 비교하면서, 불변이 보장됐고, 변경 실패 시 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를 활용하고자 하는 분들은 아래 링크를 참고하시면 도움이 될 듯싶습니다.
마치며
공부를 하며 그동안 아주 기초적인 것들을 제대로 공부하지 않았다는 것을 깨닫습니다. 좋은 기술을 배우는 것도 좋지만, 기술의 기반이 되는 기초적인 지식을 먼저 쌓는 것이 중요하다는 것을 다시금 깨달았습니다. 기초가 튼튼한 개발자가 되고 싶습니다.
출처
'Project > 서버 개발' 카테고리의 다른 글
[Project] 프로젝트 삽질기47 (feat TypeORM IN 커스텀 정렬) (0) | 2023.03.29 |
---|---|
[Project] 프로젝트 삽질기46 (feat Time Zone) (0) | 2023.02.19 |
[Project] 프로젝트 삽질기44 (feat limit, take) (0) | 2023.01.31 |
[Project] 프로젝트 삽질기43 (feat EC2 크레딧) (1) | 2023.01.14 |
[Project] 프로젝트 삽질기42 (feat 테스트 중 node.js 메모리 부족) (0) | 2022.12.20 |