"use strict"; // Day-number kernel: Howard Hinnant, "chrono-Compatible Low-Level Date Algorithms", // https://howardhinnant.github.io/date_algorithms.html (days_from_civil). No host clock, no // Date.now(), no time zone database. function daysFromCivil(y, m, d) { y = m <= 2 ? y - 1 : y; const era = Math.floor((y >= 0 ? y : y - 399) / 400); const yoe = y - era * 400; const doy = Math.floor((153 * (m + (m > 2 ? -3 : 9)) + 2) / 5) + d - 1; const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy; return era * 146097 + doe - 719468; } const EPOCH_JDN = 2440588; function toJDN(y, m, d) { return daysFromCivil(y, m, d) + EPOCH_JDN; } function isLeapGregorian(y) { return (y % 4 === 0 && y % 100 !== 0) || (y % 400 === 0); } function daysInMonth(y, m) { const dim = [31, isLeapGregorian(y) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; return dim[m - 1]; } function parseISODate(s, label) { const m = /^(-?\d{4})-(\d{2})-(\d{2})$/.exec(String(s).trim()); if (!m) throw new Error((label || "date") + " must be an ISO 8601 date YYYY-MM-DD, got: " + s); const year = parseInt(m[1], 10), month = parseInt(m[2], 10), day = parseInt(m[3], 10); if (month < 1 || month > 12) throw new Error((label || "date") + " month out of range 1-12"); if (day < 1 || day > daysInMonth(year, month)) throw new Error((label || "date") + " day out of range for that month"); return { year, month, day }; } module.exports = { slug: "countdown-to-date", title: "Countdown to a date", deck_category: "dates", description: "Computes the whole number of days, and the equivalent weeks and days, from one date to another.", inputs: [ { name: "from_date", type: "string", format: "date", required: true, description: "ISO 8601 starting date, YYYY-MM-DD" }, { name: "to_date", type: "string", format: "date", required: true, description: "ISO 8601 target date, YYYY-MM-DD, must be on or after from_date" } ], outputs: [ { name: "total_days", unit: "days", description: "Whole days from from_date to to_date" }, { name: "weeks", unit: "weeks", description: "Whole weeks in the total" }, { name: "extra_days", unit: "days", description: "Days left over after the whole weeks" } ], steps: [ "Parse from_date and to_date as proleptic Gregorian civil dates and convert both to Julian Day Numbers (Hinnant days_from_civil, cited above).", "Require to_date on or after from_date; otherwise the inputs are invalid.", "total_days = JDN(to_date) - JDN(from_date).", "weeks = floor(total_days / 7); extra_days = total_days mod 7." ], constants: [], sources: [ { kind: "url", value: "https://howardhinnant.github.io/date_algorithms.html", title: "chrono-Compatible Low-Level Date Algorithms", publisher: "Howard Hinnant", retrieved_utc: "2026-09-30T19:41:35Z", note: "day-number kernel used for the subtraction" } ], disclaimer: null, questionText(inputs) { return "How many days, weeks and days are there from " + inputs.from_date + " to " + inputs.to_date + "?"; }, run(inputs) { const a = parseISODate(inputs.from_date, "from_date"); const b = parseISODate(inputs.to_date, "to_date"); const jdnA = toJDN(a.year, a.month, a.day); const jdnB = toJDN(b.year, b.month, b.day); if (jdnB < jdnA) throw new Error("to_date must not be before from_date"); const totalDays = jdnB - jdnA; const weeks = Math.floor(totalDays / 7); const extraDays = totalDays % 7; const answer = totalDays + " days (" + weeks + " weeks and " + extraDays + " days)"; return { answer, values: { total_days: totalDays, weeks, extra_days: extraDays } }; }, examples: [ { name: "worked example", inputs: { from_date: "2026-09-30", to_date: "2026-12-25" }, expected: { answer: "86 days (12 weeks and 2 days)" }, check: "independently: Sep has 30-30=0 remaining, Oct 31 + Nov 30 + Dec 25 = 86 days; 86 = 12*7 + 2" }, { name: "test vector: same date", inputs: { from_date: "2026-01-01", to_date: "2026-01-01" }, expected: { answer: "0 days (0 weeks and 0 days)" }, check: "a date has zero days until itself" }, { name: "test vector: across a leap day", inputs: { from_date: "2024-02-01", to_date: "2024-03-01" }, expected: { answer: "29 days (4 weeks and 1 days)" }, check: "2024 is a leap year so February has 29 days; 29 = 4*7 + 1" } ] };