a tool for shared writing and social publishing
at main 2.1 kB view raw
1"use client"; 2import { useContext, useMemo } from "react"; 3import { DateTime } from "luxon"; 4import { RequestHeadersContext } from "components/Providers/RequestHeadersProvider"; 5import { useHasPageLoaded } from "components/InitialPageLoadProvider"; 6 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. 10 * 11 * @param dateString - ISO date string to format 12 * @param options - Intl.DateTimeFormatOptions for formatting 13 * @returns Formatted date string 14 * 15 * @example 16 * const formatted = useLocalizedDate("2024-01-15T10:30:00Z", { dateStyle: 'full', timeStyle: 'short' }); 17 */ 18export function useLocalizedDate( 19 dateString: string, 20 options?: Intl.DateTimeFormatOptions, 21): string { 22 const { timezone, language } = useContext(RequestHeadersContext); 23 const hasPageLoaded = useHasPageLoaded(); 24 25 return useMemo(() => { 26 // Parse the date string to Luxon DateTime 27 let dateTime = DateTime.fromISO(dateString); 28 29 // On initial page load, use header timezone. After hydration, use system timezone 30 const effectiveTimezone = !hasPageLoaded 31 ? timezone || "UTC" 32 : Intl.DateTimeFormat().resolvedOptions().timeZone; 33 34 // Apply timezone if available 35 if (effectiveTimezone) { 36 dateTime = dateTime.setZone(effectiveTimezone); 37 } 38 39 // On initial page load, use header locale. After hydration, use system locale 40 // Parse locale from accept-language header (take first locale) 41 // accept-language format: "en-US,en;q=0.9,es;q=0.8" 42 const effectiveLocale = !hasPageLoaded 43 ? language?.split(",")[0]?.split(";")[0]?.trim() || "en-US" 44 : Intl.DateTimeFormat().resolvedOptions().locale; 45 46 try { 47 return dateTime.toLocaleString(options, { locale: effectiveLocale }); 48 } catch (error) { 49 // Fallback to en-US if locale is invalid 50 return dateTime.toLocaleString(options, { locale: "en-US" }); 51 } 52 }, [dateString, options, timezone, language, hasPageLoaded]); 53}