Something went wrong. Try again.
A fully featured CLI used as an alternative to AppView applications (Bsky.app/mu.social)
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031import { UsageError } from './errors.ts';
// Times as people write them on a command line: an ISO 8601 date or date and// time, or how long ago ("30m", "2h", "1d", "1w").
const UNITS: Record<string, number> = { s: 1, m: 60, h: 3600, d: 86_400, w: 604_800 };
/** A point in time, in milliseconds since the epoch. */export function parseTime(text: string, now = Date.now()): number { const value = text.trim(); const relative = /^(\d+(?:\.\d+)?)\s*([smhdw])$/i.exec(value); if (relative) return now - Number(relative[1]) * UNITS[relative[2]!.toLowerCase()]! * 1000; // A date alone is midnight UTC; a date and time without an offset is UTC too, // so the same command means the same thing on every machine. const iso = /^\d{4}-\d{2}-\d{2}$/.test(value) ? `${value}T00:00:00Z` : /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/.test(value) ? `${value.replace(' ', 'T')}Z` : value; if (!/^\d{4}-\d{2}-\d{2}T/.test(iso)) throw new UsageError(`'${text}' is not a time: give an ISO 8601 date or time (2026-10-15, 2026-10-15T09:00:00Z), or how long ago (30m, 2h, 1d, 1w)`); const parsed = Date.parse(iso); if (Number.isNaN(parsed)) throw new UsageError(`'${text}' is not a valid time`); return parsed;}
/** A length of time in milliseconds: "500ms", "5s", "2m", "1h", or a bare number of seconds. */export function parseDuration(text: string): number { const match = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/i.exec(text.trim()); if (!match) throw new UsageError(`'${text}' is not a duration: give one like 500ms, 5s, 2m or 1h`); const unit = (match[2] ?? 's').toLowerCase(); return Number(match[1]) * (unit === 'ms' ? 1 : UNITS[unit]! * 1000);}