/* ============================================================ Session 59 (work-order 2.3) — the REAL pipeline schedule, for honest waiting states. "Awaiting next scan" told the user nothing; the truth is the cron fires at fixed UTC hours, so we can say "Grades post ~6:00 PM ET". HOURS_UTC mirrors the backend default (snapshotScheduler SNAPSHOT_HOURS_UTC = 14,19,22,1,3). If the env schedule changes, update BOTH places — a wrong time here is a lie, which is worse than the old vague copy. CommonJS so the plain-JS Jest suite can require it directly. ============================================================ */ const HOURS_UTC = [14, 19, 22, 1, 3]; /** The next scheduled run strictly after `now`, as a Date. */ function nextRunAt(now = new Date(), hours = HOURS_UTC) { const candidates = []; for (let dayOffset = 0; dayOffset <= 1; dayOffset += 1) { for (const h of hours) { const d = new Date(now.getTime()); d.setUTCDate(d.getUTCDate() + dayOffset); d.setUTCHours(h, 0, 0, 0); if (d.getTime() > now.getTime()) candidates.push(d); } } candidates.sort((a, b) => a.getTime() - b.getTime()); return candidates[0] || null; } /** "~6:00 PM ET" for the next run. Empty string when the schedule is unknown. */ function nextRunLabelET(now = new Date(), hours = HOURS_UTC) { const next = nextRunAt(now, hours); if (!next) return ''; const t = new Intl.DateTimeFormat('en-US', { timeZone: 'America/New_York', hour: 'numeric', minute: '2-digit', }).format(next); return `~${t} ET`; } module.exports = { HOURS_UTC, nextRunAt, nextRunLabelET };