/** SRS §9.4.5 — business hours 09:00–18:00, Mon–Fri (local server timezone). */ const BUSINESS_START_HOUR = 9; const BUSINESS_END_HOUR = 18; export function isBusinessHoursEnabled(): boolean { if (process.env.DEBUG_SLA_FAST_MODE === 'true') return false; return process.env.SLA_BUSINESS_HOURS !== 'false'; } export function businessMsBetween(start: Date, end: Date): number { if (end.getTime() <= start.getTime()) return 0; let total = 0; const cursor = new Date(start); while (cursor.getTime() < end.getTime()) { const day = cursor.getDay(); if (day !== 0 && day !== 6) { const windowStart = new Date(cursor); windowStart.setHours(BUSINESS_START_HOUR, 0, 0, 0); const windowEnd = new Date(cursor); windowEnd.setHours(BUSINESS_END_HOUR, 0, 0, 0); const sliceStart = Math.max(cursor.getTime(), windowStart.getTime(), start.getTime()); const sliceEnd = Math.min(end.getTime(), windowEnd.getTime()); if (sliceEnd > sliceStart) { total += sliceEnd - sliceStart; } } cursor.setDate(cursor.getDate() + 1); cursor.setHours(0, 0, 0, 0); } return total; } export function effectiveElapsedMs( track: { startTime: Date | string; metadata?: Record | null }, nowMs: number ): number { const meta = track.metadata || {}; const start = new Date(track.startTime).getTime(); const pausedAt = meta.pausedAt ? new Date(String(meta.pausedAt)).getTime() : null; const effectiveEnd = pausedAt ? Math.min(nowMs, pausedAt) : nowMs; let elapsed = isBusinessHoursEnabled() ? businessMsBetween(new Date(start), new Date(effectiveEnd)) : effectiveEnd - start; const accumulatedPause = Number(meta.accumulatedPauseMs || 0); elapsed = Math.max(0, elapsed - accumulatedPause); return elapsed; }