Uses exact calculation when possible. Very large years use a safe approximation.
(function(){
const calcBtn = document.getElementById(‘calcBtn’);
const resetBtn = document.getElementById(‘resetBtn’);
const yearInput = document.getElementById(‘christYear’);
const resultBox = document.getElementById(‘resultBox’);
// Safe JS Date boundary – keep a conservative range to avoid unreliable Date behavior
const SAFE_MIN_YEAR = -1000000;
const SAFE_MAX_YEAR = 1000000;
function daysBetweenDates(d1, d2) {
// Use UTC midnight to avoid timezone offset issues
const msPerDay = 24 * 60 * 60 * 1000;
const utc1 = Date.UTC(d1.getUTCFullYear(), d1.getUTCMonth(), d1.getUTCDate());
const utc2 = Date.UTC(d2.getUTCFullYear(), d2.getUTCMonth(), d2.getUTCDate());
return Math.round((utc2 – utc1) / msPerDay);
}
function approxDaysForFarYear(targetYear, today) {
const currentYear = today.getUTCFullYear();
// days remaining this year until Dec 25 UTC
const dec25ThisYear = new Date(Date.UTC(currentYear, 11, 25));
const daysUntilThisDec25 = daysBetweenDates(today, dec25ThisYear);
const yearsDiff = targetYear – currentYear;
// average Gregorian year length
const avgYear = 365.2425;
// approximate days to target Dec 25
const approxDays = Math.round(yearsDiff * avgYear + daysUntilThisDec25);
return approxDays;
}
function calculate() {
const raw = yearInput.value.trim();
const now = new Date();
const todayUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
let targetYear;
if (raw === ”) {
// choose upcoming Christmas: if today is after Dec 25 (or on), choose next year
const thisYearDec25 = new Date(Date.UTC(now.getUTCFullYear(), 11, 25));
targetYear = now > thisYearDec25 ? now.getUTCFullYear() + 1 : now.getUTCFullYear();
} else {
// parse integer (can be very large)
// Use Number for reasonable ranges, but for extremely large numbers we still treat as BigInt-like via string
// We’ll try to convert to Number for safe range check; if not safe, we treat as far year.
if (!/^-?d+$/.test(raw)) {
resultBox.innerHTML = ‘Invalid year. Enter digits only.‘;
return;
}
// parse as integer string
const parsed = Number(raw);
if (Number.isFinite(parsed) && Math.abs(parsed) <= 1e12) {
targetYear = Math.trunc(parsed);
} else {
// extremely large – use approximation path
// convert to BigInt for sign-check maybe, but we only need sign
const sign = raw.startsWith('-') ? -1 : 1;
// if negative or absurdly large, still attempt approximation relative to current year using string subtraction
// Convert both to BigInt if possible
try {
const targetBig = BigInt(raw);
const currentBig = BigInt(now.getUTCFullYear());
const yearsDiffBig = targetBig – currentBig;
// If absolute difference exceeds 1e9, we'll just approximate using avg year
const absDiff = yearsDiffBig BigInt(1e9)) {
// huge difference
const approx = approxDaysForFarYear(Number(now.getUTCFullYear()) + Number((yearsDiffBig > 0 ? 1 : -1) * BigInt(0)), todayUTC);
// We won’t compute precise yearsDiff as Number (unsafe), instead compute using string math:
// compute yearsDiff as decimal by subtracting string lengths:
// Simpler: show approximate message and compute approxDays via avgYear * difference (use BigInt -> string conversion)
// We’ll compute approxDays using BigInt yearsDiff when it’s not too large to convert to Number.
resultBox.innerHTML = `
Approximation for year ${raw}
The year is outside JavaScript’s reliable date range. Showing an approximate number of days using average year length (365.2425).
Approx. days: ${approx.toLocaleString()}
`;
return;
} else {
// safe to convert to Number for calculation
targetYear = Number(targetBig);
}
} catch (e) {
// BigInt not available or parse failed -> fallback to approximation
const approx = approxDaysForFarYear(Number(now.getUTCFullYear()), todayUTC);
resultBox.innerHTML = `
Approximation for year ${raw}
The year is outside JavaScript’s reliable date range. Showing an approximate number of days using average year length (365.2425).
Approx. days: ${approx.toLocaleString()}
`;
return;
}
}
}
// At this point targetYear is a Number
if (targetYear >= SAFE_MIN_YEAR && targetYear <= SAFE_MAX_YEAR) {
// build Dec 25 UTC of targetYear
const targetDate = new Date(Date.UTC(targetYear, 11, 25));
const days = daysBetweenDates(todayUTC, targetDate);
if (days === 0) {
resultBox.innerHTML = `
It’s Christmas today! 🎄
`;
} else if (days > 0) {
resultBox.innerHTML = `
${days.toLocaleString()} day(s) until Christmas ${targetYear}.
`;
} else {
// negative -> Christmas already passed; show absolute and suggest next-year
resultBox.innerHTML = `