내가 99년생이었으면 좋겠다
저번 주 부트캠프에서 치렀던 테스트 중 만 나이를 계산하는 문제가 있었다.
만 나이를 계산하는 로직을 짜는 김에 한국 나이와, 다음 생일까지 남은 일 수를 구하는 계산기를 직접 만들어보고 싶었다.
실생활에 흔히 사용되는 기능을 직접 코드로 풀어가면서 JavaScript의 Date
객체를 이해하고 활용할 수 있게 되었다. 개인적인 경험으로는 사소한 것이라도 직접 만들어보면서 친해지는 것이 효과적이고 효율적이었다.
한국식 나이 계산법은 East Asian age reckoning이라고도 불리며 태어난 순간부터 1살, 생일이 지나건 지나지 않았건 매 해를 넘기면 한 살씩 먹는다.
우리가 말하는 만 나이란 생후 첫 돌에 비로소 한 살이 되고, 매년 생일이 되어야 한 살씩 먹어간다.
외국 사람과 나이 관련해서 이야기했던 적이 있는데, 만 나이가 국제적인 나이(International age) 아니냐고 말했더니 그딴거 없고 한국만 이런 식으로 나이를 계산한다고 했다.
YYYY-MM-DD
형식의 매개 변수를 넣어 생년월일 기준Date
객체를 만든 것이birthData
- 현재 시각을 기준으로 만든
Date
객체가 할당된currentData
const calcAge = (input) => {
const birthData = new Date(input);
const currentData = new Date();
}
한국식 나이 계산은 태어난 해를 1살로 치고, 생일이 지났는지와 관계 없이 계산하는 해의 1월 1일 자정이 지나면 1살을 더한다.
const koreanAge = currentData.getFullYear() - birthData.getFullYear() + 1;
한국식 나이 계산은 간단하다. 기준일의 연도에서 생년을 빼준 후 한 살을 더해주면 된다.
만 나이 계산(일반적인 나이 계산)은 생 후 첫번째 생일이 되어야 1살이 되며, 나이를 계산하는 해에 생일이 지나야 비로소 1살을 더한다.
const realAge = new Date(currentData - birthData).getFullYear() - 1970;
Date
객체끼리도 연산이 가능하다. 타임스탬프(밀리세컨즈, 1/1000초)로 변환되어 연산을 수행한다. 연산 결과를 연도로 산출하려면 다시Date
생성자의 인자로 연산 결과를 넣어주어야 한다.
자바스크립트에서 타임스탬프는 1970년 1월 1일 자정으로부터 경과된 밀리세컨즈를 의미하기 때문에 다시 1970을 빼주어야 원하는 결과를 얻을 수 있다.
현재 시간을 담은
Date
객체는 시, 분, 초 까지 포함하고 있다. 하지만 생년월일을 담은Date
객체는 시간을 포함하지 않고 자정으로 Set 되어있다. 따라서setHours()
메소드로 현재 시간 객체의 시간 정보를 리셋할 필요가 있다.
// Syntax
setHours(hoursValue);
setHours(hoursValue, minutesValue);
setHours(hoursValue, minutesValue, secondsValue);
setHours(hoursValue, minutesValue, secondsValue, msValue);
아래 함수는
YYYY-MM-DD
포맷의 생일 정보를 인자로 전달받고, 나이와 한국 나이를 객체에 담아 반환한다.
const calcAge = input => {
const birthData = new Date(input);
const currentData = new Date();
currentData.setHours(0, 0, 0, 0);
// 나이 계산
const realAge = new Date(currentData - birthData).getFullYear() - 1970; // 만 나이 계산하기
const koreanAge = currentData.getFullYear() - birthData.getFullYear() + 1; // 한국 나이 계산하기
return {
realAge: realAge,
koreanAge: koreanAge,
}
};
- 올해 생일이 지나지 않았다면 올해의 생일까지 남은 일 수를 반환한다.
- 올해 생일이 지났다면 내년 생일까지 남은 일 수를 반환한다.
한국식 나이 계산에서 만 나이를 빼면 아래와 같다
- 올해 생일이 지났을때 -> 한국 나이 - 만 나이 = 1
- 올해 생일이 지나지 않았을때 -> 한국 나이 - 만 나이 = 2
위 명제는 아래의 조건문으로 표현할 수 있다.
if (koreanAge - 2 === realAge) { ... }
else if (koreanAge - 1 === realAge) { ... }
아래와 같은 프로세스로 Date
객체의 연산을 활용한다.
- 현 시각을 나타내는 날짜 객체를 만든다 (1)
- 생년월일 중 생년만 현재 연도로 수정한 날짜 객체를 만든다. (2)
- 만약 생일이 지났을 경우 내년 생일까지 남은 시간을 계산해야 하므로 매개 변수
correction
을 넣는다. (생일이 지나지 않았을 경우 + 0 / 지났으면 + 1)
const timeDifference = correction => {
return currentData - new Date(birthData.setFullYear(currentData.getFullYear() + correction))
};
currentData
(현재 시각 날짜 객체)
new Date(birthData.setFullYear(currentData.getFullYear() + correction))
(생일 기준 날짜 객체에서 생년을 현재 연도로 수정)
아래 조건에 따라 올해 생일이 지나지 않았을 경우 (한국나이 - 만나이 = 2)와 올해 생일이 지났을 경우 (한국나이 - 만나이 = 1) 내년 생일까지 남은 날짜를 변수
result
에 밀리세컨즈 단위로 할당한다.
let result;
if (koreanAge - 2 === realAge) {
result = timeDifference(0); // 올해 생일이 지나지 않은 경우
} else if (koreanAge - 1 === realAge) {
result = timeDifference(1); // 올해 생일이 지나 내년 생일까지 계산
}
위 연산 결과를 음수에서 양수로, 밀리세컨즈 단위에서 일 단위로 변환해야한다.
양수로 바꾸는 것은Math.abs
메소드를 사용하고, 하루는 3600분, 1분은 1000 밀리세컨즈이기 때문에 역으로 다시 나눠준다.
시간의 차이는 상관 없으니Math.floor
로 정수를 만든다.
let remaining;
.
.
remaining = Math.abs(Math.floor(result / 1000 / 3600 / 24));
만약 오늘이 생일이라면 생일까지 남은 날짜를 담은 변수
remaining
이 365가 되어야 한다. 즉 오늘이 생일이기 때문에 다음 생일까지 365일이 남은 것이다.
let today;
.
.
today = remaining === 365 ? true : false;
만 나이, 한국 나이, 다음 생일까지 남은 날짜, 오늘 생일 여부를 객체 정보로 담아 반환한다. 필요한 정보를 객체로 묶어서 반환하는 편이 사용하기 용이하기 때문이다.
return {
realAge: realAge,
koreanAge: koreanAge,
remainingAge: remaining,
isTodayBirthday: today
}
const calcAge = input => {
const birthData = new Date(input);
const currentData = new Date();
currentData.setHours(0, 0, 0, 0);
// 나이 계산
const realAge = new Date(currentData - birthData).getFullYear() - 1970; // 만 나이 계산하기
const koreanAge = currentData.getFullYear() - birthData.getFullYear() + 1; // 한국 나이 계산하기
// 다음 생일까지 날짜 계산
const timeDifference = correction => {
return currentData - new Date(birthData.setFullYear(currentData.getFullYear() + correction));
}
let result, today, remaining;
if (koreanAge - 2 === realAge) { // 생일이 지나지 않았음 (올해 생일까지 몇 일?)
result = timeDifference(0);
} else if (koreanAge - 1 === realAge) { // 생일이 지났음 (내년 생일까지 몇 일?)
result = timeDifference(1);
}
remaining = Math.abs(Math.floor(result / 1000 / 3600 / 24));
today = remaining === 365 ? true : false;
// 객체 반환
return {
realAge: realAge,
koreanAge: koreanAge,
remainingDays: remaining,
isTodayBirthday: today,
}
};
};
ⓒ Wonkook Lee
🙏🏻 잘못된 정보가 있다면 지적해주세요
오늘도 재밌게 보고 갑니다 쇽쇽