Luigit
repositories / will

will

owned by admin

src/shared/time.ts

Raw
export interface Clock {
  now(): Date
}

export const systemClock: Clock = {
  now: () => new Date(),
}

/** Deterministic clock for tests and reproducible jobs. */
export function fixedClock(iso: string): Clock {
  const at = new Date(iso)
  return { now: () => new Date(at.getTime()) }
}

export function nowIso(clock: Clock = systemClock): string {
  return clock.now().toISOString()
}

/** UTC hour key like `2026-09-12T03` used for at-most-once heartbeat claims. */
export function utcHourKey(at: Date): string {
  return at.toISOString().slice(0, 13)
}

/** ms until the next UTC hour boundary. */
export function msUntilNextHour(at: Date): number {
  const next = Date.UTC(
    at.getUTCFullYear(),
    at.getUTCMonth(),
    at.getUTCDate(),
    at.getUTCHours() + 1,
  )
  return next - at.getTime()
}

/** Day key `YYYY-MM-DD` (UTC) used for budget rollover. */
export function utcDayKey(at: Date): string {
  return at.toISOString().slice(0, 10)
}

export function addDays(at: Date, days: number): Date {
  return new Date(at.getTime() + days * 86_400_000)
}

export function isoToDate(iso: string): Date {
  const d = new Date(iso)
  if (Number.isNaN(d.getTime())) throw new Error(`invalid iso timestamp: ${iso}`)
  return d
}