Skip to content
Twilight React Playground
ثيم رائدaren

useDate

hookBeginnerserverbrowserlive demo

Formats dates and "2 hours ago" style relative times in the page language, using the browser or server Intl APIs.

import { useDate, UseDateResult } from '@salla.sa/twilight-theme-engine/hooks';

In plain words

Dates from the Salla API are strings like "2024-12-31 10:30:00". useDate() turns them into something a shopper reads: format(date) gives "December 31, 2024" on English pages and the Arabic equivalent on Arabic pages, and ago(date) gives "2 hours ago".

now is the current date and time, read when your component renders.

Signature

function useDate(): UseDateResult

interface UseDateResult {
  format: (date: DateInput, formatType?: 'full' | 'long' | 'medium' | 'short' | 'time') => string;
  ago: (date: DateInput) => string;
  now: Date;
}

// Not exported:
type DateInput =
  | string | number | Date
  | { date: string; timezone_type: number; timezone: string }
  | undefined;

Try it live

useDate() formats a date and a "time ago" in the page language. It runs in the browser here because ago() reads the clock.Try this: set minutes to 1440 (yesterday), then switch the language pill between ar and en. Clear the date to see format() fall back to today.
Storefront canvas · en · LTR
Runs in the browser…
Controls
An ISO date string. Try an empty value.
What a theme writes
import { useDate, useIsClient } from '@salla.sa/twilight-theme-engine/hooks';

export function PostDate({ publishedAt = '2024-12-31T10:30:00' }: { publishedAt?: string }) {
  const { format, ago } = useDate();
  const isClient = useIsClient(); // relative time depends on the clock: render it after hydration
  return (
    <p>
      <time dateTime={publishedAt}>{format(publishedAt)}</time>
      {isClient && <span> · {ago(publishedAt)}</span>}
    </p>
  );
}

Example

app/components/PostDate.tsx
import { useDate, useIsClient } from '@salla.sa/twilight-theme-engine/hooks';

export function PostDate({ publishedAt }: { publishedAt: string }) {
  const { format, ago } = useDate();
  const isClient = useIsClient();

  return (
    <p className="post-date">
      <time dateTime={publishedAt}>{format(publishedAt, 'long')}</time>
      {/* "ago" depends on the clock, so render it only in the browser */}
      {isClient && <span> · {ago(publishedAt)}</span>}
    </p>
  );
}

How it behaves

  • The language is useTranslation().locale. format uses Intl.DateTimeFormat; ago uses Intl.RelativeTimeFormat with numeric: auto, so one day back reads "yesterday".

  • The format types: full adds the weekday, medium (the default) and long are identical (day, long month, year), short uses the short month name, and time is a 2-digit hour and minute only.

  • ago rounds down into year (365 days), month (30 days), week, day, hour, minute and second. Anything under a second returns "just now", or "الآن" for an ar locale.

  • A { date, timezone_type, timezone } object (the PHP date shape some Salla responses use) is read from date only; timezone is ignored.

  • It has no subpath of its own: import it from @salla.sa/twilight-theme-engine/hooks. DateInput is not exported at all.

Gotchas

  • format(undefined) and format('') return today's date, not an empty string: an empty input becomes new Date(). Check for a missing date before calling it.

  • Future dates return "just now" from ago: only past differences match a unit, so "in 3 days" never appears.

  • ago and now read the clock while rendering, and the server renders in UTC while the browser uses local time. The server HTML and the first browser render can disagree (a hydration mismatch). Render relative times after mount, with useIsClient().

  • An unparseable string makes Intl throw; format catches that and returns toLocaleDateString(), which is the text "Invalid Date".

  • docs/18-hooks-api.md imports it from @salla.sa/twilight-theme-engine/hooks/useDate, a subpath that does not exist. Import from @salla.sa/twilight-theme-engine/hooks.

Related

Source and docs