"use strict"; // No day-number conversion needed: this method works purely on the (year, month) calendar // fields. No host clock, no Date.now(), no time zone database. 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: "quarter-and-fiscal-year", title: "Calendar quarter and fiscal year", deck_category: "dates", description: "Computes a date's calendar quarter and its fiscal quarter and fiscal year for a given fiscal-year start month.", inputs: [ { name: "date", type: "string", format: "date", required: true, description: "ISO 8601 date, YYYY-MM-DD" }, { name: "fiscal_year_start_month", type: "integer", required: true, min: 1, max: 12, description: "Month (1-12) the fiscal year starts in; 1 means the fiscal year equals the calendar year; 10 matches the US federal fiscal year" } ], outputs: [ { name: "calendar_quarter", description: "Q1-Q4 of the calendar year" }, { name: "fiscal_quarter", description: "Q1-Q4 of the fiscal year" }, { name: "fiscal_year", description: "The fiscal year label, named for the calendar year in which the fiscal year ends (matching the US federal convention)" } ], steps: [ "Parse the date as a proleptic Gregorian civil date.", "calendar_quarter = floor((month - 1) / 3) + 1.", "If fiscal_year_start_month is 1, the fiscal year always equals the calendar year (a fiscal year that starts and ends within the same January-December span cannot be named for a different year).", "Otherwise: if the date's month is on or after fiscal_year_start_month, the fiscal year is named for the NEXT calendar year (the fiscal year that starts this year and ends next year); if the month is before fiscal_year_start_month, it is named for the current calendar year (the fiscal year already in progress, started the prior calendar year).", "fiscal_quarter = floor(((month - fiscal_year_start_month + 12) mod 12) / 3) + 1." ], constants: [], sources: [ { kind: "url", value: "https://www.fiscal.treasury.gov/reports-statements/", title: "US federal fiscal year convention (October 1 - September 30, named for the ending calendar year)", publisher: "Bureau of the Fiscal Service, US Department of the Treasury", retrieved_utc: "2026-09-30T19:41:35Z", note: "example of the 'named for the year it ends in' fiscal-year-start convention used by this method" } ], disclaimer: null, questionText(inputs) { return "What calendar quarter and fiscal quarter/year does " + inputs.date + " fall in, given a fiscal year starting in month " + inputs.fiscal_year_start_month + "?"; }, run(inputs) { const d = parseISODate(inputs.date, "date"); const fy0 = inputs.fiscal_year_start_month; if (!Number.isInteger(fy0) || fy0 < 1 || fy0 > 12) throw new Error("fiscal_year_start_month must be an integer 1-12"); const calendarQuarter = Math.floor((d.month - 1) / 3) + 1; const fiscalYear = fy0 === 1 ? d.year : (d.month >= fy0 ? d.year + 1 : d.year); const fiscalQuarter = Math.floor(((d.month - fy0 + 12) % 12) / 3) + 1; const answer = "Calendar Q" + calendarQuarter + " " + d.year + "; fiscal Q" + fiscalQuarter + " FY" + fiscalYear; return { answer, values: { calendar_quarter: calendarQuarter, fiscal_quarter: fiscalQuarter, fiscal_year: fiscalYear } }; }, examples: [ { name: "worked example", inputs: { date: "2026-09-30", fiscal_year_start_month: 10 }, expected: { answer: "Calendar Q3 2026; fiscal Q4 FY2026" }, check: "September is calendar Q3; with an October-start fiscal year, Jul-Sep is fiscal Q4, and since month 9 < 10 the fiscal year is still named 2026" }, { name: "test vector: after the fiscal start", inputs: { date: "2025-11-15", fiscal_year_start_month: 10 }, expected: { answer: "Calendar Q4 2025; fiscal Q1 FY2026" }, check: "November is calendar Q4 2025; October-December is fiscal Q1 of the fiscal year ending in 2026 (US federal FY2026 starts Oct 1, 2025)" }, { name: "test vector: fiscal year matches calendar year", inputs: { date: "2026-05-10", fiscal_year_start_month: 1 }, expected: { answer: "Calendar Q2 2026; fiscal Q2 FY2026" }, check: "with a January-start fiscal year, fiscal figures always equal the plain calendar quarter and year" } ] };