This commit is contained in:
2026-10-18 22:42:00 +01:00
commit 2df34ab938
95 changed files with 12358 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
/**
* Human time helpers for the alarm surfaces.
*
* The takeover shows a count-up ("2s ago") rather than a server timestamp: on a
* lock screen at arm's length an RFC3339 string is unreadable, and the number
* that matters is how long the phone has been screaming. The absolute time is
* still available as the accessibility label.
*/
/** Parse a server RFC3339 string. Returns null when absent or unparseable. */
export function parseServerTime(value: string | null | undefined): Date | null {
if (!value) return null;
const ms = Date.parse(value);
return Number.isNaN(ms) ? null : new Date(ms);
}
const SECOND = 1000;
const MINUTE = 60 * SECOND;
const HOUR = 60 * MINUTE;
const DAY = 24 * HOUR;
/**
* Compact elapsed time. Deliberately coarse above a minute: the takeover updates
* every second only while the alarm is fresh, and "13m ago" is more useful than
* "13m 42s ago" on a wall of red.
*/
export function relativeTime(from: Date, now: number): string {
const elapsed = now - from.getTime();
// A clock skew between phone and server must not render "in 3 seconds".
if (elapsed < SECOND) return 'just now';
if (elapsed < MINUTE) return `${Math.floor(elapsed / SECOND)}s ago`;
if (elapsed < HOUR) return `${Math.floor(elapsed / MINUTE)}m ago`;
if (elapsed < DAY) return `${Math.floor(elapsed / HOUR)}h ago`;
return `${Math.floor(elapsed / DAY)}d ago`;
}
/** Convenience: relative time for a server string, or null when unparseable. */
export function relativeSince(value: string | null | undefined, now: number): string | null {
const date = parseServerTime(value);
return date ? relativeTime(date, now) : null;
}
/** Local wall-clock time for the accessibility label of a relative stamp. */
export function absoluteLocal(date: Date): string {
const hh = String(date.getHours()).padStart(2, '0');
const mm = String(date.getMinutes()).padStart(2, '0');
const ss = String(date.getSeconds()).padStart(2, '0');
return `${hh}:${mm}:${ss}`;
}