Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
import { daysInMonth, formatIsoDate, parseIsoDate } from "./dates_add_days.ts"; ← from dates.add-days ^1.0.0 · built alongside by fune
import { type Quarter } from "./dates_quarter_types.ts";
/** A month counted from January of year 0, back to its year and month. */
function monthFromIndex(index: number): { year: number; month: number } {
const year = Math.floor(index / 12);
return { year, month: index - year * 12 + 1 };
}
function firstDay(index: number): string {
const { year, month } = monthFromIndex(index);
return formatIsoDate({ year, month, day: 1 });
}
function lastDay(index: number): string {
const { year, month } = monthFromIndex(index);
return formatIsoDate({ year, month, day: daysInMonth(year, month) });
}
/**
* The calendar and fiscal quarter of a date. The fiscal year is given as dates,
* not a number, because "FY2027" means the year ending in 2027 to one
* organisation and the year starting in it to another.
*/
export function quarter(iso: string, fiscalYearStartMonth: number): Quarter {
if (!Number.isInteger(fiscalYearStartMonth)) {
throw new TypeError(`fiscalYearStartMonth must be an integer, received ${fiscalYearStartMonth}`);
}
if (fiscalYearStartMonth < 1 || fiscalYearStartMonth > 12) {
throw new RangeError(`fiscalYearStartMonth must be 1-12, received ${fiscalYearStartMonth}`);
}
const date = parseIsoDate(iso);
const monthsIntoYear = (date.month - fiscalYearStartMonth + 12) % 12;
const fiscalQuarter = Math.floor(monthsIntoYear / 3) + 1;
// Work in months counted from year 0 so year boundaries need no special case.
const yearStart = date.year * 12 + (date.month - 1) - monthsIntoYear;
const quarterStart = yearStart + 3 * (fiscalQuarter - 1);
if (monthFromIndex(yearStart).year < 1 || monthFromIndex(yearStart + 11).year > 9999) {
throw new RangeError(`the fiscal year containing "${iso}" is outside the supported range 0001-01-01 to 9999-12-31`);
}
return {
calendarYear: date.year,
calendarQuarter: Math.floor((date.month - 1) / 3) + 1,
fiscalQuarter,
fiscalYearStart: firstDay(yearStart),
fiscalYearEnd: lastDay(yearStart + 11),
fiscalQuarterStart: firstDay(quarterStart),
fiscalQuarterEnd: lastDay(quarterStart + 2),
};
}