JavaScript의 Date가 왜 문제인지, 그리고 이를 대체할 Temporal이 어떻게 더 일관적이고 안전한 날짜/시간 모델을 제공하는지 살펴본다.
현실 세계를 위한 프런트엔드 교육. 2018년부터.
— From set.studio
Mat “Wilto” Marquis, 2026년 1월 07일
주제:JavaScript
1월 말까지 모든 프리미엄 코스를 15% 할인받으세요!
Advert
시간은 우리 모두를 바보로 만들고, JavaScript도 그 분야에서 결코 뒤지지 않습니다. 솔직히 말해 저는 후자(자바스크립트의 그런 면)를 그다지 신경 쓰지 않는 편이었어요 — 사실 JavaScript for Everyone을 들었거나 뉴스레터를 구독하고 있다면, 제가 믿기 어렵겠지만 JavaScript의 자잘한 버릇들을 대체로 _즐긴다_는 걸 이미 알고 계실 겁니다.
저는 이음새가 보이는 걸 좋아합니다. ES-262 스펙이 아무리 형식적이고 빈틈없어 보일지라도, 어디를 봐야 하는지만 안다면 언어를 ‘비행 중에’ 만들어 온 수백 명의 사람들이 내린 좋은 결정과 나쁜 결정을 모두 볼 수 있다는 점이 좋습니다. JavaScript에는 _개성_이 있어요. 물론 기대한 대로 정확히 동작하지 않을 때도 많지만, 제게는, 알고 나면 JavaScript에는 진짜 매력이 있습니다!
하지만 언어의 한 부분에서는 그 매력이 바로 무너집니다.
js// 숫자 월(month)은 0부터 시작하지만, 연도(year)와 일(day)은 그렇지 않다: console.log( new Date(2026, 1, 1) ); // 결과: Date Sun Feb 01 2026 00:00:00 GMT-0500 (Eastern Standard Time)
Date 생성자(constructor)요.
js// 32에서 49 사이의 숫자 문자열은 2000년대로 간주된다: console.log( new Date( "49" ) ); // 결과: Date Fri Jan 01 2049 00:00:00 GMT-0500 (Eastern Standard Time) // 33에서 99 사이의 숫자 문자열은 1900년대로 간주된다: console.log( new Date( "99" ) ); // 결과: Date Fri Jan 01 1999 00:00:00 GMT-0500 (Eastern Standard Time) // ...그런데 100 이상은 0년부터 시작한다: console.log( new Date( "100" ) ); // 결과: Date Fri Jan 01 0100 00:00:00 GMT-0456 (Eastern Standard Time)
저는 Date가 정말 싫습니다.
js// 문자열 기반 날짜는 기대한 대로 동작한다: console.log( new Date( "2026/1/2" ) ); // 결과: Date Fri Jan 02 2026 00:00:00 GMT-0500 (Eastern Standard Time) // 월에 선행 0이 붙어도? 문제 없음. 1은 1이니까, 그렇죠? console.log( new Date( "2026/02/2" ) ); // 결과: Date Mon Feb 02 2026 00:00:00 GMT-0500 (Eastern Standard Time) // 형식이 약간 달라도? 좋아! console.log( new Date( "2026-02-2" ) ); // 결과: Date Mon Feb 02 2026 00:00:00 GMT-0500 (Eastern Standard Time) // 일(day)에 선행 0이 붙어도? 물론이지. 왜 안 되겠어? console.log( new Date('2026/01/02') ); // 결과: Date Fri Jan 02 2026 00:00:00 GMT-0500 (Eastern Standard Time) // 물론, 연/월/일을 하이픈으로 구분하면 얘기가 달라진다. // 그러면 _일(day)_을 틀린다. console.log( new Date('2026-01-02') ); // 결과: Date Thu Jan 01 2026 19:00:00 GMT-0500 (Eastern Standard Time)
Date는 최악입니다. 학교 가는 길 차 안에서 Java의 숙제를 급하게 베껴 썼는데, 이름까지 똑같이 적어놓고(Date) 정답은 모조리 틀린 느낌이죠. Date는 _날짜(date)_를 나타내지 않고, _시간(time)_을 나타냅니다. 내부적으로 날짜는 time value라는 숫자 값으로 저장되는데요: 유닉스 타임스탬프(Unix timestamp)를 1,000으로 나눈 밀리초 단위입니다. 물론, 유닉스 시간은 필연적으로 날짜를 암시하긴 합니다. 하지만 그래도: Date는 시간을 나타내고, 그로부터 날짜를 추론할 수 있을 뿐이죠. 끔찍합니다.
js// (JavaScript가 발표된 날인) 1995년 12월 4일 월요일 00:00:00 GMT-05의 유닉스 타임스탬프: const timestamp = 818053200; console.log( new Date( timestamp * 1000 ) ); // 결과: Date Mon Dec 04 1995 00:00:00 GMT-0500 (Eastern Standard Time)
“date”와 “time” 같은 단어는 분명 뜻이 있는데도, 뭐 — 그래요, JavaScript답네요.
Java는 1997년에 이미 자기네 Date를 폐기(deprecate)했습니다. JavaScript의 Date가 세상에 풀려난 지 몇 년 안 돼서요. 그런데 우리는 그 뒤로 지금까지 계속 이 혼돈을 짊어지고 살아왔죠. 지금까지 본 것처럼 날짜 파싱에 있어 극도로 일관성이 없고요. 로컬 타임존과 GMT 외에는 시간대(time zone)에 대한 감각도 없습니다(웹이라는 이름에 “world-wide”가 대놓고 들어가는데 말이죠). 그리고 말이 나와서 말인데 Date는 오직 그레고리력만 존중합니다. 일광 절약 시간제(DST)라는 개념은 아예 이해하지 못하고요. 뭐, 저도 똑같지만… 저는 컴퓨터로 만들어진 존재가 아니잖아요. 이런 결함들 때문에 이를 우회하기 위한 서드파티 라이브러리를 쓰는 일이 흔하고, 그중 일부는 엄청나게 _거대_합니다. 이건 성능을 갉아먹는 요소이고, 웹에 실제로 측정 가능한 피해를 준 적도 있습니다.
하지만 이것들은 제가 Date에 대해 가진 가장 큰 불만은 아닙니다. 제 불평은 파싱이나 문법이나 “개발자 경험”이나, 필수적인 우회책이 초래한 웹 전체 성능 문제나, 심지어 “date”라는 단어의 정의에 대한 것도 아닙니다. 제 문제는 Date와는 영혼 깊은 곳에서부터 맞지 않는다는 데 있어요. Date를 쓰는 건 곧 _시간의 근본적 성질에서 벗어나는 것_입니다.
JavaScript의 모든 원시(primitives) 값은 **불변(immutable)**입니다. 즉 값 자체를 바꿀 수 없다는 뜻이죠. 숫자 값 3은 ‘3’이라는 개념 외의 다른 것을 절대 나타낼 수 없습니다 — true를 ‘true’ 말고 다른 의미로 만들 수도 없고요. 이런 값들은 현실 세계에서의 의미가 구체적이고, 단단하며, 확고합니다. 우리는 3이 무엇인지 알고 있죠. 3이 아닌 어떤 다른 ‘비-3’이 될 수 없습니다. 이런 불변 데이터 타입은 **값으로 저장(by value)**되는데, 숫자 값 3을 나타내는 변수는 사실상 3을 “포함”하는 것처럼 — 즉 3처럼 동작합니다.
불변 값을 변수에 할당하면, JavaScript 엔진은 그 값의 복사본을 만들어 메모리에 저장합니다:
jsconst theNumber = 3; console.log( theNumber ); // 결과: 3
이건 “변수”에 대한 일반적인 멘탈 모델과 잘 맞습니다: theNumber는 3을 “담고” 있어요.
theNumber에 바인딩된 값을 사용해 theOtherNumber를 초기화해도 이 멘탈 모델은 유지됩니다. 또다시 3이 만들어져 메모리에 저장됩니다. 이제 theOtherNumber는 자기만의 별도 3을 담고 있다고 생각할 수 있죠.
jsconst theNumber = 3; const theOtherNumber = theNumber; console.log( theOtherNumber ); // 결과: 3;
물론 theOtherNumber에 연결된 값을 바꾼다고 해서 theNumber의 값이 바뀌진 않습니다 — 다시 말해 우리는 서로 분리된 두 개의 3을 다루고 있죠.
jsconst theNumber = 3; let theOtherNumber = theNumber; theOtherNumber = 5; console.log( theOtherNumber ); // 결과: 5; console.log( theNumber ); // 결과: 3
theOtherNumber에 바인딩된 값을 바꿀 때, 3 자체를 바꾸는 게 아니라 새로운 불변 숫자 값을 만들고 그것을 대신 바인딩하는 겁니다. 그래서 const로 선언된 변수를 건드리려 하면 에러가 나죠:
jsconst theNumber = 3; theNumber = 5; // 결과: Uncaught TypeError: invalid assignment to const 'theNumber'
const의 바인딩은 바꿀 수 없고, 3의 의미는 더더욱 바꿀 수 없습니다.
생성된 뒤에 바꿀 수 있는 데이터 타입은 **가변(mutable)**입니다. 즉 데이터 값 _자체_가 변경될 수 있습니다. 객체 값 — 배열, 맵, 셋 같은 원시가 아닌 모든 값 — 은 가변입니다.
변수(그리고 객체 프로퍼티, 함수 파라미터, 배열/셋/맵의 요소)는 위 예시에서 theNumber가 3을 “담는” 것처럼 객체를 “담을” 수는 없습니다. 변수는 원시 값 또는 **참조 값(reference value)**을 담을 수 있는데, 참조 값은 메모리에서 해당 객체가 저장된 위치를 가리키는 포인터입니다. 객체를 변수에 할당할 때는 객체 복사본을 만드는 대신, 식별자(identifier)가 메모리 내 객체의 위치에 대한 참조를 나타냅니다. 그래서 const로 선언된 변수에 바인딩된 객체도 변경할 수 있는 겁니다: _참조 값_은 바꿀 수 없지만, 객체 내부의 값들은 바꿀 수 있으니까요.
jsconst theObject = { theValue : 3 }; theObject.theValue++; console.log( theObject.theValue ); // 결과: 4
const의 바인딩은 여전히 바꿀 수 없지만, 그 바인딩이 참조하는 객체는 바꿀 수 있습니다.
참조 값을 한 변수에서 다른 변수로 할당하면, JavaScript 엔진은 객체 값 자체가 아니라 참조 값의 복사본을 만듭니다(원시 값처럼 값 그 자체의 복사본을 만드는 게 아닙니다). 두 식별자는 메모리의 같은 객체를 가리키고, 한 참조를 통해 객체를 변경하면 다른 참조에도 그대로 반영됩니다. 모두 같은 것을 참조하고 있으니까요.
jsconst theObject = { theValue : 3 }; const theOtherObj = theObject; theOtherObj.theValue++; console.log( theOtherObj.theValue ); // 결과: 4 console.log( theObject.theValue ); // 결과: 4
JavaScript의 날짜 처리에서 저를 가장 괴롭히는 지점이 바로 _이_겁니다. 달력 위의 “그 날짜”를 가리키는 값임에도, JavaScript의 날짜 값은 _가변_입니다 — Date는 생성자이고, new로 생성자를 호출하면 필연적으로 객체가 만들어지며, 모든 객체는 본질적으로 가변이니까요.
jsconst theDate = new Date(); console.log( typeof theDate ); // 결과: object
“2026년 1월 1일”은 “3”이나 “true”만큼이나 현실에서 불변의 개념인데도, 우리가 그 날짜를 표현할 수 있는 유일한 방법은 가변 데이터 구조뿐입니다.
이건 또한 Date 생성자의 인스턴스로 초기화된 어떤 변수든 참조 값을 담고 있다는 뜻이기도 합니다. 즉 메모리에 있는 데이터 값을 가리키며, 그 값은 어떤 참조를 통해서든 변경될 수 있죠.
jsconst theDate = new Date(); console.log( theDate.toDateString() ); // 결과: Tue Dec 30 2025 theDate.setMonth( 10 ); console.log( theDate.toDateString() ); // 결과: Sun Nov 30 2025
다시 말하지만, 월 10이 _11월_이라는 사실은 일단 넘어갑시다.
현실 세계의 날짜는 의미가 확고한데도, Date 인스턴스와 상호작용하는 과정에서 의도하지 않게 그 인스턴스를 바꿔버릴 수 있습니다:
jsconst today = new Date(); const addDay = theDate => { theDate.setDate( theDate.getDate() + 1 ); return theDate; }; console.log(`Today is ${ today.toLocaleDateString() }, tomorrow is ${ addDay( today ).toLocaleDateString() }.`); // 결과: Today is 12/31/2025. Tomorrow is 1/1/2026.
지금까진 괜찮죠? 오늘은 오늘이고 내일은 내일이며, 세상은 올바르게 굴러갑니다. 이걸 코드베이스에 커밋하고 하루를 마무리해도 이해할 만해요. 그런데 출력 순서를 약간만 바꾸면 어떨까요?
jsconst today = new Date(); const addDay = theDate => { theDate.setDate( theDate.getDate() + 1 ); return theDate; }; console.log(`Tomorrow will be ${ addDay( today ).toLocaleDateString() }. Today is ${ today.toLocaleDateString() }.`); // 결과: Tomorrow will be 1/1/2026. Today is 1/1/2026.
무슨 일이 벌어졌는지 보셨나요? 변수 today는 new Date()로 생성된 객체에 대한 참조를 나타냅니다. today를 addDay 함수에 인자로 넘기면, 파라미터 theDate는 값의 복사본이 아니라 참조 값의 복사본 — 즉 오늘을 나타내는 동일 객체를 가리키는 두 번째 참조 — 가 됩니다. 다음날을 계산하려고 그 값을 조작하는 순간, 우리는 불변 복사본을 다루는 게 아니라 메모리 속 가변 객체를 조작하게 됩니다. 오늘이 내일이 되어버리죠. 매는 매부리의 목소리를 듣기 힘들어지고, 중심은 ‘버틴다’는 개념에 대해 점점 불안해 보이기 시작하고… 뭐, 그런 겁니다.
이쯤이면 제가 Date를 칭찬하러 온 게 아니라는 건 느끼셨을 텐데요, 예상과 달리 저는 여기서 Date를 묻어버리려 왔습니다. 맞습니다. Date는 곧 끝납니다. 더 이상 쓰지 말아야 하는 수준으로 “deprecated(사용 비권장)”가 될 거예요 — 즉 “영원히 남아 있겠지만 가능하면 더는 쓰지 마라” 정도의 의미죠. 머지않아 우리는 Date를 전면 대체하는 객체를 — 마침내 — 갖게 됩니다: Temporal.
눈썰미 좋은 분들은 제가 “Date를 대체하는 객체”라고 했지 “생성자”라고 하지 않았다는 걸 눈치채셨을지도 모르겠네요. Temporal은 생성자가 아니고, 브라우저 개발자 콘솔도 생성자로 호출하려고 하면 똑같이 말해줄 겁니다.
jsconst today = new Temporal(); // Uncaught TypeError: Temporal is not a constructor
제게 물어보신다면, 시간과 관련된 무언가에 Temporal이라는 이름은 훨씬 더 좋은 이름입니다.
대신 Temporal은 **네임스페이스 객체(namespace object)**입니다 — Math 객체처럼 정적 프로퍼티와 메서드로 이루어진 일반 객체죠.
jsconsole.log( Temporal ); /* 결과(확장): Temporal { … } Duration: function Duration() Instant: function Instant() Now: Temporal.Now { … } PlainDate: function PlainDate() PlainDateTime: function PlainDateTime() PlainMonthDay: function PlainMonthDay() PlainTime: function PlainTime() PlainYearMonth: function PlainYearMonth() ZonedDateTime: function ZonedDateTime() Symbol(Symbol.toStringTag): "Temporal" */
저는 이게 Date에 비해 즉시 이해가 됩니다. Temporal이 포함하는 클래스와 네임스페이스 객체를 통해 두 시점 사이의 기간(duration)을 계산할 수 있고, 시간대 지정 여부에 따라 시점을 표현할 수도 있으며, Now 프로퍼티를 통해 현재 시각에 접근할 수도 있습니다. Temporal.Now는 자체적인 프로퍼티와 메서드를 가진 네임스페이스 객체를 참조합니다:
jsconsole.log( Temporal.Now ); /* 결과(확장): Temporal.Now { … } instant: function instant() plainDateISO: function plainDateISO() plainDateTimeISO: function plainDateTimeISO() plainTimeISO: function plainTimeISO() timeZoneId: function timeZoneId() zonedDateTimeISO: function zonedDateTimeISO() Symbol(Symbol.toStringTag): "Temporal.Now" <prototype>: Object { … } */
Temporal은 낡아빠진 Date처럼 “오늘 날짜”를 가져오는 합리적이고 평이한 방법을 제공합니다. Now 프로퍼티에 plainDateISO() 메서드가 있죠. 우리는 시간대를 따로 지정하지 않았기 때문에(Temporal 덕분에 이제 지정도 가능해졌지만) 이 메서드는 현재 시간대 기준으로 오늘 날짜를 반환합니다 — 제 경우엔 EST입니다.
jsconsole.log( Temporal.Now.plainDateISO() ); /* 결과(확장): Temporal.PlainDate 2025-12-31 <prototype>: Object { … } */
plainDateISO가 이미 포맷된, 날짜만의 값으로 결과를 준다는 점에 주목하세요. 계속 보시면 나중에 다시 등장합니다.
—잠깐. 이거 익숙한데요:
jsconst nowTemporal = Temporal.Now.plainDateISO(); const nowDate = new Date(); console.log( nowTemporal ); /* 결과(확장): Temporal.PlainDate 2025-12-31 <prototype>: Object { … } */ console.log( nowDate ); /* 결과(확장): Date Tue Dec 31 2025 11:05:52 GMT-0500 (Eastern Standard Time) <prototype>: Date.prototype { … } */
설마—…
jsconst rightNow = Temporal.Now.instant(); console.log( typeof rightNow ); // object
네, 여전히 현재 날짜를 나타내는 가변 객체를 다루고 있습니다. 제가 가장 무서운 목소리로 말하면서, 손전등을 턱 밑에 딱 받쳐 들고 말이죠. 얼핏 보면 이게 Date에 대한 제 큰 불만을 전혀 해결하지 못하는 것처럼 보일 수도 있어요.
하지만 여기서는 언어의 성질상 어쩔 수 없는 부분도 있습니다. 날짜는 현실 세계의 복잡한 값을 나타내고, 복잡한 데이터는 복잡한 데이터 구조를 요구합니다. JavaScript에서 그건 곧 객체죠. 차이는 Date 인스턴스와 비교했을 때, Temporal 객체와 _상호작용하는 방식_에 있습니다. 그리고 — 늘 그렇듯 — 마법은 프로토타입 체인에 있습니다:
jsconst nowTemporal = Temporal.Now.plainDateISO(); console.log( nowTemporal.__proto__ ); /* 결과(확장): Object { … } add: function add() calendarId: >> constructor: function PlainDate() day: >> dayOfWeek: >> dayOfYear: >> daysInMonth: >> daysInWeek: >> daysInYear: >> equals: function equals() era: >> eraYear: >> inLeapYear: >> month: >> monthCode: >> monthsInYear: >> since: function since() subtract: function subtract() toJSON: function toJSON() toLocaleString: function toLocaleString() toPlainDateTime: function toPlainDateTime() toPlainMonthDay: function toPlainMonthDay() toPlainYearMonth: function toPlainYearMonth() toString: function toString() toZonedDateTime: function toZonedDateTime() until: function until() valueOf: function valueOf() weekOfYear: >> with: function with() withCalendar: function withCalendar() year: >> yearOfWeek: >> Symbol(Symbol.toStringTag): "Temporal.PlainDate" <get calendarId()>: function calendarId() <get day()>: function day() <get dayOfWeek()>: function dayOfWeek() <get dayOfYear()>: function dayOfYear() <get daysInMonth()>: function daysInMonth() <get daysInWeek()>: function daysInWeek() <get daysInYear()>: function daysInYear() <get era()>: function era() <get eraYear()>: function eraYear() <get inLeapYear()>: function inLeapYear() */
바로 눈에 띄는 건, 우리가 다루는 Temporal 객체의 세부 정보를 접근(access), 포맷(format), 조작(manipulate)하기 위한 메서드와 프로퍼티가 아주 많다는 점입니다. 놀랄 건 없죠 — 약간의 학습 곡선이 있는 건 사실이지만, 가끔 MDN에 들르는 정도면 충분하고, 대체로 이름 그대로 동작합니다. Date와의 큰 차이는, 근본적으로 어떻게 동작하느냐입니다:
jsconst nowTemporal = Temporal.Now.plainDateISO(); // 현재 로컬 날짜: console.log( nowTemporal ); /* 결과(확장): Temporal.PlainDate 2025-12-30 <prototype>: Object { … } */ // 현재 로컬 연도: console.log( nowTemporal.year ); // 결과: 2025 // 현재 로컬 날짜와 시간: console.log( nowTemporal.toPlainDateTime() ); /* 결과(확장): Temporal.PlainDateTime 2025-12-30T00:00:00 <prototype>: Object { … } */ // 이 날짜가 Europe/London 시간대를 나타낸다고 지정: console.log( nowTemporal.toZonedDateTime( "Europe/London" ) ); /* 결과(확장): Temporal.ZonedDateTime 2025-12-30T00:00:00+00:00[Europe/London] <prototype>: Object { … } */ // 이 날짜에 하루 더하기: console.log( nowTemporal.add({ days: 1 }) ); /* Temporal.PlainDate 2025-12-31 <prototype>: Object { … } */ // 이 날짜에 한 달과 하루를 더하고, 2년 빼기: console.log( nowTemporal.add({ months: 1, days: 1 }).subtract({ years: 2 }) ); /* Temporal.PlainDate 2024-01-31 <prototype>: Object { … } */ console.log( nowTemporal ); /* 결과(확장): Temporal.PlainDate 2025-12-30 <prototype>: Object { … } */
이 변환들 중 어떤 것도 수동으로 새 객체를 띄울 필요가 없고, nowTemporal이 참조하는 객체의 값이 변하지 않는다는 점이 보이시나요? Date와 달리, Temporal 객체와 상호작용하는 메서드들은 우리가 작업 중인 인스턴스를 수정하지 않고 새로운 Temporal 객체를 결과로 반환합니다. 새 인스턴스를 만들고 그 컨텍스트에서 쓰거나 기존 인스턴스를 바꿔야 하는 방식이 아니죠. 그래서 nowTemporal.add({ months: 1, days: 1 }).subtract({ years: 2 })처럼 add와 subtract를 체이닝할 수 있습니다.
물론 여전히 객체를 다루고 있으니, 현실 세계의 값을 표현하는 가변 데이터 구조를 다루는 건 맞습니다:
jsconst nowTemporal = Temporal.Now.plainDateISO(); nowTemporal.someProperty = true; console.log( nowTemporal ); /* 결과(확장): Temporal.PlainDate 2026-01-05 someProperty: true <prototype>: Object { … }
…하지만 그 Temporal 객체가 표현하는 값 자체는, 보통의 상호작용 과정에서 변경되도록 설계된 게 아닙니다. 즉 객체는 여전히 가변에 가깝지만, 현실 세계의 날짜/시간 의미를 바꿔버릴 수 있는 방식으로 그 객체를 사용할 수밖에 없는 상황에 갇히지 않습니다. 저는 이 정도면 만족합니다.
그럼 아까 Date로 썼던, 그 허술한 “오늘은 X, 내일은 Y” 스크립트를 다시 봅시다. 먼저 Date로 고쳐볼게요. 오늘을 나타내는 인스턴스를 수정하지 않도록 Date의 별도 인스턴스 두 개를 사용하게 만들면 됩니다:
jsconst today = new Date(); const addDay = theDate => { const tomorrow = new Date(); tomorrow.setDate( theDate.getDate() + 1 ); return tomorrow; }; console.log(`Tomorrow will be ${ addDay( today ).toLocaleDateString() }. Today is ${ today.toLocaleDateString() }.`); // 결과: Tomorrow will be 1/1/2026. Today is 12/31/2025.
고맙지만, 저는 싫습니다.
그래요, 좋아요. Date가 처음 웹에 비틀거리며 등장한 날부터 지금까지 늘 그랬듯, 일은 됩니다. addDay 함수 안에서 Date의 새 인스턴스를 만들었기 때문에 today의 값을 무심코 바꾸는 일은 없습니다. 말은 길지만 작동은 하죠. 거기에 1을 더하는데, 그게 하루를 더한다는 뜻이라는 걸 그냥 알고 있어야 합니다. 그리고 템플릿 리터럴에서는 현재 시간을 포함하지 않는 문자열 형식으로 날짜를 얻어내기 위해 계속 JavaScript를 살살 달래야 하죠. 기능적이지만 장황합니다.
이제 Temporal로 다시 작성해 봅시다:
jsconst today = Temporal.Now.plainDateISO(); console.log(`Tomorrow will be ${ today.add({ days: 1 }) }. Today is ${ today }.`); // 결과: Tomorrow will be 2026-01-01. Today is 2025-12-31.
이제야 말이 됩니다.
훨씬 좋죠. 더 간결하고, 더 날카롭고, 실수할 여지도 훨씬 적습니다. 우리는 시간 없이 오늘 날짜만 원하고, plainDateISO가 반환하는 객체(그리고 여기서 파생되는 모든 새로운 Temporal 객체)는 문자열로 강제 변환하지 않아도 그 형식을 그대로 유지합니다. 포맷: 체크.
우리는 “오늘 날짜에 하루를 더한 값”을 출력하고 싶고, 파싱 추측 없이 분명하게 “하루를 더하라”고 말하는 방식으로 하고 싶습니다: 체크 그리고 체크.
무엇보다도, 원래의 today 객체가 의도치 않게 바뀌는 위험을 원치 않습니다 — add 메서드를 호출한 결과는 항상 새 Temporal 객체이기 때문이죠: 체크.
Temporal은 Date에 비해 엄청난 개선이 될 겁니다. 제가 “될” 거라고 말하는 이유는, 아직 본격적으로 쓰기엔 완전히 준비가 되지 않았기 때문이에요. 제안된 Temporal 객체의 드래프트 스펙은 표준화 프로세스의 3단계(stage three)에 도달했습니다. 즉 공식적으로 “구현 권장(recommended for implementation)” 상태입니다 — 아직 JavaScript 자체의 지속적인 개발을 규정하는 표준의 일부는 아니지만, 브라우저가 실험해볼 만큼은 충분히 가까워졌다는 뜻이죠. 초기 실험 결과가 스펙을 더 다듬는 데 쓰일 수 있으니, 아직 모든 것이 확정된 건 아닙니다. 웹 표준은 원래 반복적(iterative)인 과정이니까요.
여기서 여러분과 제가 할 일이 생깁니다. Temporal이 최신 버전의 Chrome과 Firefox에 들어왔고 — 조만간 다른 브라우저도 뒤따를 겁니다 — 이제 우리가 직접 써보고 테스트해볼 때입니다. Date에 대해서는 우리가 아무 말도 할 수 없었지만, Temporal은 최종 구현이 확정되기 전에 실험해볼 수 있어요.
곧 JavaScript는 합리적이고 현대적인 날짜 처리를 갖게 될 것이고, 우리는 마침내 Date를 고무줄, 맞지 않는 병뚜껑, 정체불명의 열쇠, 반쯤 남은 것 같은 AA 배터리와 함께 잡동사니 서랍 맨 뒤로 밀어 넣을 수 있게 될 겁니다 — 여전히 존재하고, 여전히 웹 플랫폼의 피할 수 없는 일부겠지만, 더 이상 날짜를 다루는 우리의 첫 번째이자 마지막이자 유일한 방법은 아니게 되겠죠. 그리고 우리는 기다리기만 하면 됩니다— 음, 잠깐만요. 숫자 좀 빠르게 굴려볼게요:
jsconst today = Temporal.Now.plainDateISO(); const jsShipped = Temporal.PlainDate.from( "1995-12-04" ); const sinceDate = today.since( jsShipped, { largestUnit: 'year' }); console.log( `${ sinceDate.years } years, ${ sinceDate.months } months, and ${ sinceDate.days } days.` );
Run
물론 Date를 대체하기 가장 좋은 시점은 1995년이었겠지만, 뭐 어때요: 두 번째로 좋은 시점은 Temporal.Now겠죠?
이 글이 마음에 드셨나요?Open Collective을 통해 팁 남기기로 저희를 후원할 수 있습니다.
독립 프런트엔드 개발자이자 디자이너. Javascript For Web Designers, JavaScript for Everyone의 저자이며, 취미 수집가.
Mat의 JavaScript 코스 확인하기 Mat “Wilto” Marquis 더 알아보기
뉴스레터
수천 명의 구독자와 함께, 주 2회 발행되는 고품질 큐레이션 디자인/개발/테크 링크 뉴스레터를 받아보세요.
짧게.~5개 링크, 주 2회 소화 가능.~1–2분이면 읽기 끝 큐레이션.사람이 직접 큐레이션(비-AI) 무료.비용 0, 스팸 절대 없음
이메일을 입력하세요
구독
이름
로딩 중입니다. 잠시만 기다려 주세요…
Powered by Postmark - 개인정보 처리방침
From set.studio