a tool for shared writing and social publishing
1"use client"; 2import { useContext, useMemo } from "react"; 3import { DateTime } from "luxon"; 4import { RequestHeadersContext } from "components/Providers/RequestHeadersProvider"; 5import { useInitialPageLoad } 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 isInitialPageLoad = useInitialPageLoad(); 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 = isInitialPageLoad 31 ? timezone 32 : Intl.DateTimeFormat().resolvedOptions().timeZone; 33 34 // Apply timezone if available 35 if (effectiveTimezone) { 36 dateTime = dateTime.setZone(effectiveTimezone); 37 } 38 39 // Parse locale from accept-language header (take first locale) 40 // accept-language format: "en-US,en;q=0.9,es;q=0.8" 41 const locale = language?.split(",")[0]?.split(";")[0]?.trim() || "en-US"; 42 43 return dateTime.toLocaleString(options, { locale }); 44 }, [dateString, options, timezone, language, isInitialPageLoad]); 45}