/** * @file Spend pace from the daily cost series (`daily_costs` of GET * /api/pricing/cost, already in local dates): the average cost per day over * the last 7 days, the month to date, and a month-end forecast that carries * that pace over the days left in the month. * @author Nguyễn Ngọc Trí Vĩ */ export interface SpendPace { /** Average cost per day over the 7 days ending today (today included). */ perDay7: number; /** Spend since the 1st of this month. */ monthToDate: number; /** monthToDate + perDay7 × the days left after today. */ forecastMonth: number; } /** * @param daily `{date: "YYYY-MM-DD", cost}` per local day, any order. * @param today Today's local date, `YYYY-MM-DD`. */ export function spendPace(daily: Array<{ date: string; cost: number }>, today: string): SpendPace { const [y, m, d] = today.split("-").map(Number) as [number, number, number]; const day = (offset: number) => { const t = new Date(Date.UTC(y, m - 1, d + offset)); return t.toISOString().slice(0, 10); }; const weekStart = day(-6); const monthStart = today.slice(0, 8) + "01"; let week = 0; let mtd = 0; for (const r of daily) { if (r.date > today) continue; if (r.date >= weekStart) week += r.cost; if (r.date >= monthStart) mtd += r.cost; } const daysInMonth = new Date(Date.UTC(y, m, 0)).getUTCDate(); const perDay7 = week / 7; return { perDay7, monthToDate: mtd, forecastMonth: mtd + perDay7 * (daysInMonth - d) }; }