export function timeSince(dateString: string): string { if (!dateString) { return ""; } const d = new Date(dateString.endsWith("Z") ? dateString : `${dateString}Z`); if (Number.isNaN(d.getTime())) { return ""; } const diffMs = Date.now() - d.getTime(); const mins = Math.floor(diffMs / 60000); if (mins < 1) { return "just now"; } if (mins < 60) { return `${mins}m ago`; } const hours = Math.floor(mins / 60); if (hours < 24) { return `${hours}h ago`; } const days = Math.floor(hours / 24); if (days < 7) { return `${days}d ago`; } return `${Math.floor(days / 7)}w ago`; } export function timeBetween(startStr: string, endStr: string): string { if (!startStr || !endStr) { return ""; } const start = new Date(startStr.endsWith("Z") ? startStr : `${startStr}Z`); const end = new Date(endStr.endsWith("Z") ? endStr : `${endStr}Z`); if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) { return ""; } const diffMs = end.getTime() - start.getTime(); const mins = Math.floor(diffMs / 60000); if (mins < 60) { return `${mins}m`; } const hours = Math.floor(mins / 60); if (hours < 24) { return `${hours}h`; } return `${Math.floor(hours / 24)}d`; } export function waitTimeColor(dateString: string): "green" | "yellow" | "red" | "" { if (!dateString) { return ""; } const d = new Date(dateString.endsWith("Z") ? dateString : `${dateString}Z`); const hours = (Date.now() - d.getTime()) / 3600000; if (hours < 4) { return "green"; } if (hours < 24) { return "yellow"; } return "red"; } export function formatDateTime(value: string): string { if (!value) { return ""; } const normalized = value.endsWith("Z") ? value : `${value}Z`; const date = new Date(normalized); if (Number.isNaN(date.getTime())) { return value; } const datePart = date.toLocaleDateString("en-CA"); const timePart = date.toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit", hour12: false, }); const tz = date.toLocaleTimeString(undefined, { timeZoneName: "short" }).split(" ").pop(); return `${datePart} ${timePart} ${tz ?? ""}`.trim(); } export function getWaitTimeTextClass(color: "green" | "yellow" | "red" | ""): string | undefined { if (color === "green") { return "text-green-600"; } if (color === "yellow") { return "text-yellow-600"; } if (color === "red") { return "text-red-600"; } return undefined; } export function toDateInputValue(value: string | null | undefined): string { if (!value) { return ""; } return value.split("T")[0] ?? value; } export function toDateTimeLocalInputValue(value: string | null | undefined): string { if (!value) { return ""; } const date = new Date(value); if (Number.isNaN(date.getTime())) { return ""; } const pad = (part: number) => String(part).padStart(2, "0"); return [ date.getFullYear(), "-", pad(date.getMonth() + 1), "-", pad(date.getDate()), "T", pad(date.getHours()), ":", pad(date.getMinutes()), ].join(""); }