JavaScript의 Date.getMonth()는 왜 0부터 시작하는가
JavaScript로 Date객체 만지다 한 번쯤은 겪는 상황시간을 거슬러 올라가는 여정 🕰️1. C언어의 time 구조체 (1970년대)2. Java의 Date 클래스 (1995년)3. JavaScript의 탄생 (1995년)웹 브라우저를 위한 새로운 언어10일 만에 탄생한 JavaScriptDate객체의 운명적인 선택현재와 미래: 각자의 해결책Java와 JavaScript의 다른 길맺음말
JavaScript로 Date객체 만지다 한 번쯤은 겪는 상황
> "아니, 12월인데 왜 11이 나오는 거죠? 🤔"
> "앗! 1월인데 왜 0이... 😱"
const date = new Date(); console.log(date.getMonth()); // 12월인데 11이 출력됩니다 // 흔히 저지르는 실수 const christmas = new Date(2024, 12, 25); // 의도: 2024년 12월 25일 console.log(christmas); // 실제: 2025년 1월 25일 😅
JavaScript의 Date객체는 우리가 알던 달력과는 조금 다른 방식을 보여줍니다.
1월은 0이 되고, 12월은 11이 되는 이 독특한 방식의 비밀은 무엇일까요?
시간을 거슬러 올라가는 여정 🕰️
1. C언어의 time 구조체 (1970년대)
// tm 구조체 구현 struct tm { int tm_mon; // 월 (0-11) }; // 1월은 0, 12월은 11 if (time_info->tm_mon == 0) { printf("1월입니다\n"); }
tm구조체는 왜 zero-based(0-based) 방식을 사용했을까요? 무슨 장단점이 있었을까요?
장점
- 메모리 효율성
- 1970년대 초기 컴퓨터의 제한된 메모리 환경
- 0부터 시작하는 인덱싱으로 메모리 주소 계산이 더 효율적
- 바이너리 연산에서의 이점
- 배열 처리의 일관성
// C언어에서의 월 이름 배열 처리 char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; printf("%s", months[time_info->tm_mon]); // 직접 인덱싱 가능
단점
- 인간의 직관적인 달력 개념과 불일치
- 데이터 표현 시 항상 변환 작업 필요
- 개발자의 실수 가능성 증가
2. Java의 Date 클래스 (1995년)
// 혼란스러운 월 표현 Date date = new Date(); int month = date.getMonth(); // 12월이면 11이 반환됨 // 실제 사용시 항상 +1을 해야 함 System.out.println("현재 월: " + (month + 1));
Java는 C언어의 time 구조체의 0-based month표현을 가져와 Date 클래스를 설계했습니다.
이 직관적이지 않은 방식은 많은 개발자들을 혼란스럽게 만들었습니다.
Java의 개선 노력
Java 진영에서는 이 한계를 인식하고 개선하기위한 시도를 합니다. 2년 뒤인 1997년 JDK 1.1에서 Calendar 클래스를 도입하게되죠.
1. Calendar 클래스 도입 (1997년)
Calendar calendar = Calendar.getInstance(); int month = calendar.get(Calendar.MONTH); // 여전히 0-11 사용 -> 한계점
2. Joda-Time 라이브러리로 대안 제시
3. java.time 패키지로 최종 해결 (2014년)
// Java 8 LocalDate today = LocalDate.now(); int month = today.getMonthValue(); // 1-12 사용
3. JavaScript의 탄생 (1995년)
*Java와 JavaScript는 둘 다 1995년에 출시되었습니다.
- Java: 1995년 5월 23일 (Sun Microsystems)
- JavaScript: 1995년 12월 4일 (Netscape)
웹 브라우저를 위한 새로운 언어
1995년, 넷스케이프는 웹 브라우저에서 동작하는 가벼운 프로그래밍 언어가 필요했습니다. 당시 썬 마이크로시스템즈에서 개발한 Java가 큰 인기를 얻고 있었고, 넷스케이프는 이에 대응할 새로운 언어를 원했죠.
10일 만에 탄생한 JavaScript
- Brendan Eich가 단 10일 만에 첫 버전 개발
- Mocha(코드명) → LiveScript(베타) → JavaScript(정식)로 이름 변경
- 빠른 개발을 위해 Java의 많은 API를 그대로 차용
Date객체의 운명적인 선택
2014년, JavaScript의 Date 객체 설계에 대한 한 개발자의 문제 제기에 Brendan Eich는 이렇게 답했습니다.
"Java 1.0 beta에서 가져온 것입니다. 시간이 없어서 그대로 사용했죠."
JavaScript의 Date.getMonth()가 0부터 시작하는 것은 C언어에서 시작된 역사적인 결정이 Java를 거쳐 JavaScript까지 이어진 결과입니다. 비록 직관적이지 않지만, 이 방식은 당시의 기술적 제약과 개발 일정 속에서 내려진 선택이었습니다.
*C언어의 time 구조체 → Java의 Date 클래스 → JavaScript의 Date 객체로 이어지는 영향
현재와 미래: 각자의 해결책
Java와 JavaScript의 다른 길
Java가 18년에 걸쳐 날짜/시간 API를 개선해온 것과 달리, JavaScript의 Date 객체는 거의 변화가 없었습니다. 다만 JavaScript 생태계는 다른 방식으로 이 문제를 해결해왔습니다.
Java: 점진적 개선의 길
- 1995년: Date 클래스 (0-based month)
- 1997년: Calendar 클래스 (여전히 0-based)
- 2014년: java.time 패키지 (드디어 1-based month)
JavaScript: 커뮤니티 중심의 해결의 길
- 커뮤니티 중심의 해결책 - moment.js (레거시지만 안정적) - day.js (가볍고 사용하기 쉬움) - date-fns (현대적이고 함수형)
- 표준화를 향한 움직임 - TC39의 Temporal API 제안 - 1-based month 등 직관적인 날짜 처리 방식 도입 예정
JavaScript 개발자를 위한 현재의 선택지
- 내장 Date 객체 사용 시 - 항상 0-based month 주의 - 유틸리티 함수로 감싸서 사용
- 대안 라이브러리 활용 (day.js, date-fns 등) - 프로젝트 상황에 맞는 라이브러리 선택 - 일관된 날짜 처리 방식 유지
맺음말
JavaScript의 Date 객체가 0부터 시작하는 월 표현을 사용하게 된 것은 단순한 우연이 아닙니다.
C언어의 메모리 효율성을 위한 선택이 Java를 거쳐, 급박했던 JavaScript 개발 일정 속에서 그대로 이어진 결과였죠.
Java가 18년에 걸쳐 점진적으로 개선해 온 것과 달리, JavaScript는 커뮤니티 중심의 다양한 해결책을 제시해왔습니다. moment.js, day.js, date-fns와 같은 라이브러리들이 그 증거이죠.
이제 JavaScript도 TC39의 Temporal API를 통해 새로운 변화를 준비하고 있습니다. 과거의 제약에서 벗어나 더 직관적인 날짜 처리를 향해 나아가고 있는 것이죠. 그때까지는 우리가 선택할 수 있는 다양한 대안들을 활용하면서, JavaScript의 발전을 함께 지켜보면 좋겠습니다.