만나이 계산기 핵심 로직: 생일 경계·윤년·D-day 정확도 구현
나이 계산은 단순히 현재연도 - 출생연도로 끝나지 않습니다.
생일 전/후 경계, 2월 29일 출생자, 잘못된 날짜 입력, 시차로 인한 일수 오차까지 처리해야 결과를 신뢰할 수 있습니다.
- 도구 바로가기: 만나이 계산기
문제: 나이 계산에서 실제로 자주 틀리는 지점
1) 생일 전인데 나이를 1살 더해버리는 오류
연도 차이만 쓰면 생일이 지나지 않았을 때 오답이 납니다.
2) 날짜 문자열 파싱 신뢰성 문제
브라우저별 new Date('YYYY-MM-DD') 해석 차이로 예상치 못한 결과가 나올 수 있습니다.
3) 윤년 출생자(2월 29일) 다음 생일 계산
평년에는 2월 29일이 없으므로, 다음 생일 기준일을 별도로 안전하게 잡아야 합니다.
4) 일수 계산 시 타임존 오차
시/분이 섞인 상태로 차이를 구하면 1일 단위 D-day가 흔들릴 수 있습니다.
원리: 안전 파싱 + UTC 일수 계산 + 경계 조건 분리
H3. 날짜 파싱은 숫자 분해 후 유효성 재검증
YYYY-MM-DD를 직접split('-')new Date(y, m-1, d, 12, 0, 0)로 생성- 다시
getFullYear/getMonth/getDate로 원본과 일치하는지 검증
이렇게 하면 2026-02-31 같은 값은 즉시 무효 처리됩니다.
H3. 만 나이는 생일 경과 여부로 보정
- 기본값:
targetYear - birthYear - 아직 생일 전이면
-1 - 최소 0으로 클램프
H3. 총 일수는 UTC 기준으로 계산
- 날짜를
Date.UTC(year, month, day)로 변환 - 두 UTC 타임스탬프 차이를 86,400,000으로 나눠 일수화
로컬 시각/서머타임 변화 영향을 줄여 D-day가 안정됩니다.
H3. 다음 생일은 “해당 연도 후보 → 이미 지났으면 다음 해”
- 출생 월/일 기준 후보 생일 생성
- 올해 후보가 기준일보다 이전이면 다음 해 후보 사용
- 2월 29일은 해당 연도의 마지막 유효일(평년 2/28)로 보정
핵심 코드: 렌더 루프에서 계산 + 출력 일괄 처리
const toDate = (value) => {
if (!value) return null;
const [y, m, d] = value.split('-').map(Number);
if (!y || !m || !d) return null;
const parsed = new Date(y, m - 1, d, 12, 0, 0, 0);
const isValid =
parsed.getFullYear() === y &&
parsed.getMonth() === (m - 1) &&
parsed.getDate() === d;
return isValid ? parsed : null;
};
const dayDiff = (a, b) => {
const toUTCDate = (d) => Date.UTC(d.getFullYear(), d.getMonth(), d.getDate());
return Math.floor((toUTCDate(b) - toUTCDate(a)) / 86400000);
};
const getNextBirthday = (b, t) => {
const month = b.getMonth();
const day = b.getDate();
const safeDate = (y) => {
const lastDay = new Date(y, month + 1, 0).getDate();
return new Date(y, month, Math.min(day, lastDay), 12, 0, 0, 0);
};
let candidate = safeDate(t.getFullYear());
if (dayDiff(t, candidate) < 0) candidate = safeDate(t.getFullYear() + 1);
return candidate;
};
핵심은 입력 검증 → 계산 → 표시를 한 렌더 흐름으로 유지해 상태 불일치를 줄인 점입니다.
예외 처리: 신뢰 가능한 결과를 위한 방어선
1) 생년월일/기준일 누락
둘 중 하나라도 없으면 계산 대신 안내 메시지 표시.
2) 생년월일 > 기준일
논리적으로 불가능한 입력이므로 결과를 숨기고 오류 안내.
3) 세는나이 표시 토글
요구사항에 따라 한국식 나이는 체크박스로 ON/OFF 가능하게 분리.
4) 복사 API 실패 폴백
navigator.clipboard 실패 시 textarea + execCommand('copy')로 대체.
5) 초기값 안정화
기준일이 비어 있으면 오늘 날짜(ISO)로 자동 세팅해 첫 진입 UX를 보장.
내부 링크: 같이 쓰면 좋은 계산 흐름
요약
만나이 계산기 구현의 포인트는 다섯 가지입니다.
- 날짜 파싱을 직접 검증해 잘못된 입력 차단
- 만 나이는 생일 경계 보정으로 정확도 확보
- 일수 계산은 UTC 기반으로 오차 최소화
- 2월 29일 출생자 생일을 연도별 유효일로 보정
- 입력/복사/초기값 예외 처리로 실사용 안정성 강화
FAQ
Q1. 왜 new Date('YYYY-MM-DD')를 바로 쓰지 않나요?
브라우저/환경별 해석 차이와 타임존 이슈를 줄이기 위해 숫자 분해 + 재검증 방식을 사용합니다.
Q2. 2월 29일 출생자는 평년에 언제 생일로 계산되나요?
해당 월의 마지막 유효일을 사용해 평년에는 2월 28일 기준으로 계산합니다.
Q3. 총 개월 수와 만 나이는 왜 다르게 보일 수 있나요?
개월 수는 “일(day) 단위 경과”를 반영하고, 만 나이는 “생일 도달 여부”를 기준으로 계산하기 때문입니다.
Q4. 기준일을 미래로 넣어도 되나요?
가능합니다. 특정 미래 시점의 만 나이와 다음 생일까지 남은 일수를 확인할 수 있습니다.