export function toIso8601Full(date: Date): string { const yearN = date.getFullYear(); const isNegativeYear = yearN <= 0; const year = isNegativeYear ? pad(1 - yearN, 6) : pad(yearN, 6); const signedYear = (isNegativeYear ? "-" : "+") + year; const month = pad(date.getMonth() + 1); const day = pad(date.getDate()); const hour = pad(date.getHours()); const minute = pad(date.getMinutes()); const second = pad(date.getSeconds()); const ms = pad(date.getMilliseconds(), 3); const dateString = `${signedYear}-${month}-${day}T${hour}:${minute}:${second}.${ms}`; const tzOffset = -date.getTimezoneOffset(); if (tzOffset === 0) { return `${dateString}Z`; } else { const offsetSign = tzOffset > 0 ? "+" : "-"; const offsetHours = pad(Math.floor(Math.abs(tzOffset) / 60)); const offsetMinutes = pad(Math.abs(tzOffset) % 60); return `${dateString}${offsetSign}${offsetHours}:${offsetMinutes}`; } } export function toIso8601FullUTC(date: Date): string { const yearN = date.getUTCFullYear(); const isNegativeYear = yearN <= 0; const year = isNegativeYear ? pad(1 - yearN, 6) : pad(yearN, 6); const signedYear = (isNegativeYear ? "-" : "+") + year; const month = pad(date.getUTCMonth() + 1); const day = pad(date.getUTCDate()); const hour = pad(date.getUTCHours()); const minute = pad(date.getUTCMinutes()); const second = pad(date.getUTCSeconds()); const ms = pad(date.getUTCMilliseconds(), 3); return `${signedYear}-${month}-${day}T${hour}:${minute}:${second}.${ms}Z`; } const pad = (num: number, len = 2) => String(Math.abs(num)).padStart(len, "0"); export function getRelativeTimeUnit( date: Date, now: Date = new Date(), ): Parameters { const diffMs = date.getTime() - now.getTime(); const seconds = diffMs / 1000; const minutes = seconds / 60; const hours = minutes / 60; const days = hours / 24; const weeks = days / 7; const months = days / 30; const quarters = months / 3; const years = days / 365; if (Math.abs(years) >= 1) return [Math.round(years), "year"]; if (Math.abs(quarters) >= 1) return [Math.round(quarters), "quarter"]; if (Math.abs(months) >= 1) return [Math.round(months), "month"]; if (Math.abs(weeks) >= 1) return [Math.round(weeks), "week"]; if (Math.abs(days) >= 1) return [Math.round(days), "day"]; if (Math.abs(hours) >= 1) return [Math.round(hours), "hour"]; if (Math.abs(minutes) >= 1) return [Math.round(minutes), "minute"]; return [Math.round(seconds), "second"]; }