🎂 Age Calculator
exact · zodiac · milestones
Calculate exact age in years, months, days — plus fun facts and upcoming milestones
const asOfDateInput = document.getElementById('asOfDate');
const todayBtn = document.getElementById('todayBtn');
const swapBtn = document.getElementById('swapBtn');
const calculateBtn = document.getElementById('calculateBtn');
const presetBtns = document.querySelectorAll('[data-preset]');
// Result spans
const ageYearsSpan = document.getElementById('ageYears');
const ageDetailSpan = document.getElementById('ageDetail');
const totalMonthsSpan = document.getElementById('totalMonths');
const totalWeeksSpan = document.getElementById('totalWeeks');
const totalDaysSpan = document.getElementById('totalDays');
// Fun facts
const zodiacSign = document.getElementById('zodiacSign');
const birthstone = document.getElementById('birthstone');
const birthFlower = document.getElementById('birthFlower');
const birthDayOfWeek = document.getElementById('birthDayOfWeek');
// Birthday
const nextBirthdayDate = document.getElementById('nextBirthdayDate');
const birthdayCountdown = document.getElementById('birthdayCountdown');
const milestoneList = document.getElementById('milestoneList');
// Life stats
const heartbeatCount = document.getElementById('heartbeatCount');
const earthOrbits = document.getElementById('earthOrbits');
const sleepHours = document.getElementById('sleepHours');
// Set today's date as default for "as of"
function setTodayAsOf() {
const today = new Date();
const yyyy = today.getFullYear();
const mm = String(today.getMonth() + 1).padStart(2, '0');
const dd = String(today.getDate()).padStart(2, '0');
asOfDateInput.value = `${yyyy}-${mm}-${dd}`;
}
// Initialize with today
setTodayAsOf();
// If DOB is empty, set a default
if (!dobInput.value) {
dobInput.value = '1990-01-01';
}
// Calculate age function
function calculateAge() {
const dobStr = dobInput.value;
const asOfStr = asOfDateInput.value;
if (!dobStr || !asOfStr) {
alert('Please select both dates');
return;
}
const dob = new Date(dobStr);
const asOf = new Date(asOfStr);
if (dob > asOf) {
alert('Birth date cannot be after the "as of" date');
return;
}
// Calculate difference in years, months, days
let years = asOf.getFullYear() - dob.getFullYear();
let months = asOf.getMonth() - dob.getMonth();
let days = asOf.getDate() - dob.getDate();
// Adjust for negative days
if (days < 0) { months--; // Get last day of previous month const lastMonth=new Date(asOf.getFullYear(),
asOf.getMonth(), 0); days=lastMonth.getDate() - dob.getDate() + asOf.getDate(); } // Adjust for negative
months if (months < 0) { years--; months +=12; } // Update age displays
ageYearsSpan.textContent=`${years} years`; ageDetailSpan.textContent=`${years} years, ${months} months,
${days} days`; // Calculate total days, weeks, months const diffTime=asOf - dob; const
diffDays=Math.floor(diffTime / (1000 * 60 * 60 * 24)); const diffWeeks=Math.floor(diffDays / 7); const
diffMonths=years * 12 + months; totalDaysSpan.textContent=diffDays.toLocaleString();
totalWeeksSpan.textContent=diffWeeks.toLocaleString();
totalMonthsSpan.textContent=diffMonths.toLocaleString(); // Fun facts based on birth date
updateFunFacts(dob); // Next birthday and milestones updateBirthdayInfo(dob, asOf); // Life stats
(approximate) updateLifeStats(years, diffDays); } // Update zodiac, birthstone, etc. function
updateFunFacts(dob) { const month=dob.getMonth() + 1; const day=dob.getDate(); // Zodiac signs const
zodiacs=[ { sign: 'Capricorn' , start: [1,1], end: [1,19] }, { sign: 'Aquarius' , start: [1,20], end:
[2,18] }, { sign: 'Pisces' , start: [2,19], end: [3,20] }, { sign: 'Aries' , start: [3,21], end: [4,19]
}, { sign: 'Taurus' , start: [4,20], end: [5,20] }, { sign: 'Gemini' , start: [5,21], end: [6,20] }, {
sign: 'Cancer' , start: [6,21], end: [7,22] }, { sign: 'Leo' , start: [7,23], end: [8,22] }, {
sign: 'Virgo' , start: [8,23], end: [9,22] }, { sign: 'Libra' , start: [9,23], end: [10,22] }, {
sign: 'Scorpio' , start: [10,23], end: [11,21] }, { sign: 'Sagittarius' , start: [11,22], end: [12,21]
}, { sign: 'Capricorn' , start: [12,22], end: [12,31] } ]; let zodiac='Capricorn' ; for (let z of
zodiacs) { if (month===z.start[0] && day>= z.start[1] || month === z.end[0] && day <= z.end[1]) { if
(z.start[0]===1 && z.start[1]===1 && month===12) continue; // avoid capricorn double zodiac=z.sign;
break; } } zodiacSign.textContent=zodiac; // Birthstones const stones={ 1: 'Garnet' , 2: 'Amethyst'
, 3: 'Aquamarine' , 4: 'Diamond' , 5: 'Emerald' , 6: 'Pearl' , 7: 'Ruby' , 8: 'Peridot' ,
9: 'Sapphire' , 10: 'Opal' , 11: 'Topaz' , 12: 'Turquoise' }; birthstone.textContent=stones[month]
|| 'Unknown' ; // Birth flowers const flowers={ 1: 'Carnation' , 2: 'Violet' , 3: 'Daffodil' ,
4: 'Daisy' , 5: 'Lily' , 6: 'Rose' , 7: 'Larkspur' , 8: 'Gladiolus' , 9: 'Aster' , 10: 'Marigold' ,
11: 'Chrysanthemum' , 12: 'Poinsettia' }; birthFlower.textContent=flowers[month] || 'Unknown' ; //
Day of week born const days=['Sunday', 'Monday' , 'Tuesday' , 'Wednesday' , 'Thursday' , 'Friday'
, 'Saturday' ]; birthDayOfWeek.textContent=days[dob.getDay()]; } // Update birthday and milestones
function updateBirthdayInfo(dob, today) { const birthMonth=dob.getMonth(); const
birthDay=dob.getDate(); // Next birthday let nextBirthday=new Date(today.getFullYear(), birthMonth,
birthDay); if (nextBirthday < today) { nextBirthday=new Date(today.getFullYear() + 1, birthMonth,
birthDay); } // Format next birthday const options={ year: 'numeric' , month: 'long' ,
day: 'numeric' }; nextBirthdayDate.textContent=nextBirthday.toLocaleDateString(undefined, options);
// Days until next birthday const diffTime=nextBirthday - today; const diffDays=Math.ceil(diffTime /
(1000 * 60 * 60 * 24)); birthdayCountdown.textContent=`in ${diffDays} day${diffDays !==1 ? 's' : ''
}`; // Calculate age at next birthday let nextAge=nextBirthday.getFullYear() - dob.getFullYear(); if
(nextBirthday < new Date(dob.getFullYear() + nextAge, dob.getMonth(), dob.getDate())) { nextAge--; }
// Milestones (upcoming 5-year marks) const currentAge=today.getFullYear() - dob.getFullYear();
const milestones=[]; for (let i=5; i <=100; i +=5) { if (i> currentAge && i <= currentAge + 25) {
milestones.push(i); } } let milestoneHtml='' ; milestones.forEach(m=> {
const milestoneDate = new Date(dob.getFullYear() + m, dob.getMonth(), dob.getDate());
const yearsFromNow = m - currentAge;
milestoneHtml += `
${m} years (in ${yearsFromNow}
year${yearsFromNow !== 1 ? 's' : ''})`;
});
if (milestoneHtml === '') {
milestoneHtml = '
No upcoming 5-year milestones';
}
milestoneList.innerHTML = milestoneHtml;
}
// Approximate life stats
function updateLifeStats(years, days) {
// Heartbeats (approx 70 bpm)
const heartbeats = Math.round(days * 24 * 60 * 70);
heartbeatCount.textContent = '~' + (heartbeats / 1e6).toFixed(1) + 'M';
// Earth orbits
earthOrbits.textContent = years;
// Sleep hours (assuming 8 hours/day)
const sleepHrs = days * 8;
sleepHours.textContent = '~' + (sleepHrs / 1000).toFixed(1) + 'k';
}
// Event listeners
calculateBtn.addEventListener('click', calculateAge);
todayBtn.addEventListener('click', () => {
setTodayAsOf();
calculateAge();
});
swapBtn.addEventListener('click', () => {
const dob = dobInput.value;
const asOf = asOfDateInput.value;
if (dob && asOf) {
dobInput.value = asOf;
asOfDateInput.value = dob;
calculateAge();
}
});
presetBtns.forEach(btn => {
btn.addEventListener('click', () => {
const preset = btn.getAttribute('data-preset');
if (preset) {
dobInput.value = preset;
calculateAge();
}
});
});
// Auto-calculate on page load
window.addEventListener('load', calculateAge);
// Also calculate when inputs change (optional)
dobInput.addEventListener('change', calculateAge);
asOfDateInput.addEventListener('change', calculateAge);
})();