forked from
leaflet.pub/leaflet
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 { 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 console.log("tz", effectiveTimezone);
35
36 // Apply timezone if available
37 if (effectiveTimezone) {
38 dateTime = dateTime.setZone(effectiveTimezone);
39 }
40
41 // On initial page load, use header locale. After hydration, use system locale
42 // Parse locale from accept-language header (take first locale)
43 // accept-language format: "en-US,en;q=0.9,es;q=0.8"
44 const effectiveLocale = !hasPageLoaded
45 ? language?.split(",")[0]?.split(";")[0]?.trim() || "en-US"
46 : Intl.DateTimeFormat().resolvedOptions().locale;
47
48 try {
49 return dateTime.toLocaleString(options, { locale: effectiveLocale });
50 } catch (error) {
51 // Fallback to en-US if locale is invalid
52 return dateTime.toLocaleString(options, { locale: "en-US" });
53 }
54 }, [dateString, options, timezone, language, hasPageLoaded]);
55}