import { useCallback, useEffect, useState } from 'react'; function formatLocalTime(timezone: string, hour12: boolean): string | undefined { try { return new Intl.DateTimeFormat('en', { timeZone: timezone, hour: 'numeric', minute: '2-digit', hour12, }).format(new Date()); } catch { return undefined; } } function getTimezoneAbbr(timezone: string): string | undefined { try { return new Intl.DateTimeFormat('en', { timeZone: timezone, timeZoneName: 'short', }) .formatToParts(new Date()) .find((p) => p.type === 'timeZoneName')?.value; } catch { return undefined; } } export type LocalTimeInfo = { time: string; abbr: string | undefined; }; /** * Returns the current time (and timezone abbreviation) in the given IANA * timezone, updated every minute. Returns undefined when timezone is * undefined or invalid. */ export function useLocalTime( timezone: string | undefined, hour12: boolean = true, ): LocalTimeInfo | undefined { const compute = useCallback((): LocalTimeInfo | undefined => { if (!timezone) return undefined; const time = formatLocalTime(timezone, hour12); if (!time) return undefined; return { time, abbr: getTimezoneAbbr(timezone) }; }, [timezone, hour12]); const [info, setInfo] = useState(compute); useEffect(() => { setInfo(compute()); const id = window.setInterval(() => setInfo(compute()), 60_000); return () => window.clearInterval(id); }, [compute]); return info; }