const now = new Date();
자바스크립트의 Date 객체를 생성할 수 있는 코드이다. 위 코드를 사용하면 현재 시간을 표현하는 값을 now에 저장할 수 있다. 외에도 Date 객체는 특정 시간에 대한 값을 저장하거나, 비교하는 등의 메서드를 제공해 자바스크립트 코드로 시간을 다룰 수 있게 해 준다.
예약 서비스를 만들며 '요일별 운영 시간'을 설정하는 기능을 구현하다가, 이 기능에 Date 객체를 활용하기에는 근본적인 한계가 있음을 마주쳤다. 우리가 설정하고자 하는 건 특정 날짜에 종속되지 않는 시간이었지만, 자바스크립트의 Date 객체는 날짜 없이 시간만을 독립적으로 설정할 수 없다.
위 문제는 라이브러리를 통해 해결했다. 예약 서비스 내의 다른 기능에서 시간 연산이나 비교가 더 필요해질 여지가 있다고 판단되었기 때문에 날짜/시간 관련 라이브러리를 체크하고, 내가 원했던 대로 시간 데이터만 독립적으로 조작할 수 있는 luxon을 도입했다. (luxon 사용에 대한 얘기는 다음 기회에 써 봐야겠다... ✏️)
하지만 의문이 들었다. 자바를 사용하는 백엔드 쪽에서는 LocalTime이라는 클래스를 사용해 아주 간단한 코드로!! 시간 정보만을 객체로 만들고 있는 걸 봐서 더 그랬다.
LocalTime lt = LocalTime.of(15, 0);
// 15:00
그럼 자바스크립트는 왜 이런 걸까? 보다 유연하고 편리하게 시간을 다룰 수 있지 않았을까? 이 글에서는 이런 궁금증에서 출발해 Date 객체에 대해 더 알아보고, 그 과정에서 알게 된 Temporal에 대한 내용을 다룬다.
mdn web docs - Date
자세한 사용법과 예제는 위 문서에서 확인할 수 있다.
객체 생성하기
문자열이나 숫자 값 등을 활용해 특정 시점을 지정하거나, 현재 시점을 객체로 저장할 수 있다.
new Date(): 인수 없이 호출하면 현재 날짜와 시간이 저장된 객체가 반환된다.new Date(value): UNIX 타임스탬프 값(1970년 1월 1일 00:00:00 UTC를 기준으로 밀리초 단위의 시간)을 사용해 호출할 수 있다.new Date(dateString): 파싱 가능한 형태의 문자열로 표현한 날짜/시간 정보를 사용해 호출할 수 있다. 즉 "December 23, 2024 10:05:00" 등을 전달할 수 있다. 단, 해당 파싱은 브라우저 간 일관성이 보장되지 않기 때문에 사용하지 않을 것을 권장하고 있다.new Date(year, monthIndex, day, hours, minutes, seconds, miliseconds): 각각의 구성 요소를 정해진 범위의 숫자로 전달할 수 있다. 이떄 최소한 연/월은 포함되어야 하며, 누락된 요소의 경우 기본값이 저장된다.getter / setter 사용하기
getFullYear(), getMonth(), getDate(), getDay()등의 메서드를 통해 객체의 구성 요소를 가져올 수 있다. 이때 date는 날짜, day는 요일에 해당한다. 또한 month, day와 같은 값은 인덱스로 반환된다.setFullYear(), setMonth(), setDate(), setTime() 등을 사용하면 객체의 구성요소를 변경할 수도 있다.시간 비교하기
Date 객체는 숫자형의 타임스탬프 값으로 변환될 수 있기 때문에, 이를 이용해 시간을 비교하는 것이 가능하다. 단 연, 월, 일의 길이는 타임스탬프에서 항상 일정하지 않기 때문에 (윤년, 월별 날짜수 등의 영향을 받는다) 이를 사람이 인식하는 기간으로 표현하는 데는 어려움이 생긴다. 문서의 예제에서도 주로 특정 동작을 수행하는 데 걸리는 시간을 측정하는 상황을 다루고 있다.
Fixing JavaScript Date - Getting Start
위 글은 자바스크립트의 또 다른 날짜/시간 라이브러리인 moment.js, 그리고 앞으로 얘기할 Temporal에 참여한 Maggie Pint의 블로그다. 글에서는 Date 객체가 갖는 문제를 (더 심각한 순으로) 다음과 같이 나열하고 있다.
보충 💡
- 불변성 immutable과 가변성 mutable 개념이 익숙하지 않다면 문서를 확인해 보자.
- DST는 Daylight Saving Time, 서머타임을 의미한다. 한국에서는 서머타임을 적용하지 않아서 낯설지만 간략히 소개하면 낮이 긴 하절기에 시간대를 원래보다 한 시간 당기는 제도라고 한다.
- 그레고리력은 현재 세계 표준으로 사용되는 달력으로, 400년에 윤년이 97번 돌아온다.
자바스크립트는 초기 설계 당시 열흘 만에 만들어졌다. 이렇듯 시간이 부족한 상황에서 날짜 데이터에 대한 요구사항을 해결하기 위해 기존에 나와 있던 Java의 Date 클래스를 참조했고, 자연스레 해당 클래스가 갖던 문제점까지 공유하게 되었다.
실제로 자바의 경우 해당 문제 해결을 위해 자바 8 버전부터 java.time이라는 새로운 패키지를 도입하고, 위에서 언급된 시간대 처리, 가변성 보유 등의 문제를 해결하면서 기존의 Date 클래스를 글 초반에 언급한 LocalDate, LocalTime 클래스 등으로 대체하게 되었다고 한다.
자바스크립트에서는 어땠을까? 위 문제 중 일부는 Date 객체를 수정하는 선에서 해결 가능했다.
setDate()같은 기존의 api보다 직관적인 api (예를 들면 addDate())를 추가하면 연산 api의 사용이 어렵다는 문제도 해결할 수 있을 것이다.반면 해결할 수 없는 문제가 있었다. Maggie Pint의 다음 블로그 글이 이를 설명하고 있다.
Date 객체의 가변성
Date 객체는 setter를 통해 값을 변경할 수 있다. setter가 기존 인스턴스를 수정하는 대신 새로운 인스턴스를 반환하게 하는 등 불변성을 보장하면 에러에 덜 취약해지겠지만, 이러한 변경은 기존에 가변성을 활용해 작성되어 있던 코드를 망가트릴 것이다.
일관되지 않은 파싱
자바스크립트에서 날짜/시간 문자열의 형식은 ISO 8601을 따른다. 이는 국제적으로 통용되는 날짜와 시간에 대한 표준이기도 하다.
ISO 8601에서는 날짜 정보만을 갖는 date-only form과 여기에 시간 정보가 결합된 date-time form을 정의하고 있다. 자바스크립트에서는 이 포맷을 해석할 수 있다. 그리고 시간대가 정의되지 않았다면, date-only form은 표준 시간대로, date-time form은 로컬 시간대로 추론된다.
예를 들어 시스템이 한국 시간대를 따르고 있을 때 다음과 같이 Date 객체를 생성한다고 해 보겠다.
const dateTime = new Date("2024-12-23T00:00");
const date = new Date("2024-12-23");
여기서 dateTime은 한국 시간 00시 00분에 해당하는 값을 갖는다. 반면 날짜만 입력한 date는 표준 시간 00시 00분, UTC+9인 한국 시간으로는 09시 00분에 해당하는 값을 갖게 된다.
원래 ISO 8601 표준에서는, 시간대가 정의되지 않았을 경우 로컬 시간대로 해석되어야 한다고 정했다. 위의 예시에서 두 변수는 모두 한국 시간대를 기준으로 추론되어야 하는 것이다. 하지만 ES5에서 이와 반대로 시간대가 정의되지 않았을 때 표준 시간대로 추론하게 되었고, 이 오류를 ISO 8601에 맞춰 로컬 시간대로 수정하고자 시도했을 때 시간 정보가 이전과 다르게 해석된다는 사용자들의 버그 리포트가 발생하면서 현재처럼 포맷에 따라 다른 시간대 추론이 정착하게 되었다고 한다.
A blessing and curse of JavaScript is that it is currently the world’s most popular programming language.
원문에서는 위와 같은 설명과 함께, 이 문제들을 두 개의 원칙 아래에 두고 있다.
1. Web compatibility: ECMAScript는 현재 표준과 충돌하는 수정을 적용할 수 없다.
2. Web Reality: 코드가 현재 동작하고 있다면, 이후의 표준도 이 동작이 유지될 것을 보장해야 한다.
결론적으로 이미 만들어진 코드가 계속 작동할 수 있어야 하기 때문에, 이 문제들을 고칠 수 없다는 것이다. 그럼 자바스크립트에서도 java.time 패키지처럼 새로운 걸 만들면 안 될까? 🧐
이러한 문제를 해결하기 위해 새로운 객체 Temporal이 제안되었다. Temporal은 다음 해결책을 적용해, 기존 Date 객체가 갖던 문제점들을 해소하고자 한다.
또한 위에서 소개한 자바의 LocalTime, LocalDate처럼 날짜 정보와 시간 정보를 독립적으로 다룰 수 있도록 지원한다. (처음에 Date 객체에 대해 느꼈던 불편함도 Temporal을 통해 해소할 수 있을 것이다! 😄)
사실 Date 공식 문서에서도 Temporal을 소개하고 있지만, "아직 프로덕션에는 적합하지 않다"고 설명한다. 현재 Temporal은 Stage 3에 올라와 있는데, 완성된 명세를 바탕으로 구현 주체나 사용자들에게 피드백을 받는 단계라고 한다.
보충 💡
- Stage 3은 TC39 프로세스의 절차로, ECMAScript 기술 위원회인 TC39와 제안 프로세스에 대해서는 아래 글에서 읽어 볼 수 있다.
ECMAScript와 TC39
개발 중인 서비스에서 직접 적용해 볼 수 없는 건 아쉽지만, Temporal을 통해 Date보다 더 발전된 형태로 시간을 다뤄볼 날이 기대된다. ✨