// Date formatting for the Headscale views. The sidecar already turned protobuf's zero timestamp into null, // so null genuinely means "never" here and every helper says so rather than printing a fake date. export function timeAgo(iso: string | null): string { if (!iso) return 'never'; const seconds = Math.round((Date.now() - new Date(iso).getTime()) / 1000); if (!Number.isFinite(seconds)) return 'unknown'; if (seconds < 0) return 'just now'; if (seconds < 60) return 'just now'; const minutes = Math.round(seconds / 60); if (minutes < 60) return `${minutes}m ago`; const hours = Math.round(minutes / 60); if (hours < 24) return `${hours}h ago`; const days = Math.round(hours / 24); if (days < 365) return `${days}d ago`; return `${Math.round(days / 365)}y ago`; } /** "in 3d" / "5h ago" — signed, for expiry dates that may be either side of now. */ export function timeUntil(iso: string | null): string { if (!iso) return 'never'; const seconds = Math.round((new Date(iso).getTime() - Date.now()) / 1000); if (!Number.isFinite(seconds)) return 'unknown'; if (seconds < 0) return timeAgo(iso); const minutes = Math.round(seconds / 60); if (minutes < 60) return `in ${Math.max(1, minutes)}m`; const hours = Math.round(minutes / 60); if (hours < 24) return `in ${hours}h`; return `in ${Math.round(hours / 24)}d`; } export function fullDate(iso: string | null): string { if (!iso) return 'never'; return new Date(iso).toLocaleString(); }