a tool for shared writing and social publishing

only use server tz on initial page load

+11 -3
+11 -3
src/hooks/useLocalizedDate.ts
··· 2 2 import { useContext, useMemo } from "react"; 3 3 import { DateTime } from "luxon"; 4 4 import { RequestHeadersContext } from "components/Providers/RequestHeadersProvider"; 5 + import { useInitialPageLoad } from "components/InitialPageLoadProvider"; 5 6 6 7 /** 7 8 * Hook that formats a date string using Luxon with timezone and locale from request headers. 9 + * On initial page load, uses the timezone from request headers. After hydration, uses the system timezone. 8 10 * 9 11 * @param dateString - ISO date string to format 10 12 * @param options - Intl.DateTimeFormatOptions for formatting ··· 18 20 options?: Intl.DateTimeFormatOptions, 19 21 ): string { 20 22 const { timezone, language } = useContext(RequestHeadersContext); 23 + const isInitialPageLoad = useInitialPageLoad(); 21 24 22 25 return useMemo(() => { 23 26 // Parse the date string to Luxon DateTime 24 27 let dateTime = DateTime.fromISO(dateString); 25 28 29 + // On initial page load, use header timezone. After hydration, use system timezone 30 + const effectiveTimezone = isInitialPageLoad 31 + ? timezone 32 + : Intl.DateTimeFormat().resolvedOptions().timeZone; 33 + 26 34 // Apply timezone if available 27 - if (timezone) { 28 - dateTime = dateTime.setZone(timezone); 35 + if (effectiveTimezone) { 36 + dateTime = dateTime.setZone(effectiveTimezone); 29 37 } 30 38 31 39 // Parse locale from accept-language header (take first locale) ··· 33 41 const locale = language?.split(",")[0]?.split(";")[0]?.trim() || "en-US"; 34 42 35 43 return dateTime.toLocaleString(options, { locale }); 36 - }, [dateString, options, timezone, language]); 44 + }, [dateString, options, timezone, language, isInitialPageLoad]); 37 45 }