TanStack Start v1で異なるロケールに対応した日付フォーマットを実装する方法

地域固有の形式で日付を表示する

問題

日付には普遍的な表示形式が存在しません。10/12/2025という表記は、米国では10月12日を意味しますが、英国では12月10日を意味します。「Oct 12, 2025」と記述することは、英語の月名と特定の順序規則を前提としています。すべての地域には、日、月、年の順序、区切り文字の選択、月名を完全に表記するか省略するかなど、独自の日付形式に対する期待があります。アプリケーションが単一の固定形式で日付を表示すると、ほとんどの地域のユーザーにとって違和感があり、混乱を招きます。

ユーザーは、日常的に学習し使用している形式で日付が表示されることを期待しています。ある対象者にとって自然に見える日付が、別の対象者にとっては曖昧または不快に感じられる可能性があります。ロケールに対応した書式設定がなければ、日付はユーザーエクスペリエンスを損ない、アプリケーションをより専門性に欠けたものに見せる摩擦の原因となります。

解決策

日付値を、順序、区切り文字、月名に関する地域規則に従った文字列に変換することで、ユーザーのロケールに基づいて日付をフォーマットします。React-intlは、ブラウザの組み込み国際化APIを使用して各ロケールに対する正しいルールを自動的に適用する書式設定関数とコンポーネントを提供します。これらのツールに日付値とオプションの書式設定オプションを渡すことで、アプリケーションはユーザーの言語と地域に対して明確かつ自然な出力を生成します。

このアプローチにより、各ロケールに対して書式設定ロジックを手動で実装することなく、日付が正しく表示されることが保証されます。書式設定はユーザーのロケールに適応し、日付を即座に認識可能にし、認知的負荷を軽減します。

手順

1. useIntlフックを使用して日付をフォーマットするコンポーネントを作成する

useIntlフックを使用してformatDateメソッドにアクセスします。このメソッドは日付の値をロケールに対応した文字列に変換します。

import { useIntl } from "react-intl";

export function EventDate({ date }: { date: Date }) {
  const intl = useIntl();

  return (
    <time dateTime={date.toISOString()}>
      {intl.formatDate(date, {
        year: "numeric",
        month: "long",
        day: "numeric",
      })}
    </time>
  );
}

formatDateメソッドは、ロケールの日付表示規則を適用します。optionsオブジェクトは、日付のどの部分を表示するか、およびその詳細レベルを制御します。フォーマットされた文字列は、コンポーネントツリーの上位にあるIntlProviderによって提供されるロケールに適応します。

2. 事前定義されたオプションを使用して特定のスタイルで日付をフォーマットする

短い数値形式の日付や長い記述形式の日付など、日付フォーマットスタイルを制御するために異なるオプションの組み合わせを渡します。

import { useIntl } from "react-intl";

export function ArticleMetadata({ publishedAt }: { publishedAt: Date }) {
  const intl = useIntl();

  const shortDate = intl.formatDate(publishedAt, {
    year: "numeric",
    month: "short",
    day: "numeric",
  });

  const longDate = intl.formatDate(publishedAt, {
    year: "numeric",
    month: "long",
    day: "numeric",
    weekday: "long",
  });

  return (
    <div>
      <p>Published: {shortDate}</p>
      <p>Full date: {longDate}</p>
    </div>
  );
}

monthオプションは、numeric2-digitshortlongnarrowなどの値を受け入れます。weekdayオプションは曜日を追加します。各ロケールは独自の規則に従ってこれらのオプションを解釈し、出力がユーザーの期待に一致することを保証します。

3. 宣言的なフォーマットにはFormattedDateコンポーネントを使用する

FormattedDateコンポーネントを使用して日付を宣言的にレンダリングします。このコンポーネントはformatDateメソッドと同じフォーマットオプションを受け入れます。

import { FormattedDate } from "react-intl";

export function OrderSummary({ orderDate }: { orderDate: Date }) {
  return (
    <div>
      <h2>Order placed on</h2>
      <FormattedDate
        value={orderDate}
        year="numeric"
        month="long"
        day="numeric"
      />
    </div>
  );
}

FormattedDateコンポーネントは、デフォルトでフォーマットされた日付をReactフラグメントとしてレンダリングします。IntlProviderコンテキストからロケールを使用し、命令型APIと同じフォーマット規則を適用します。このアプローチは、コンポーネントツリーのその部分でフォーマットされた日付のみが必要な場合に適しています。

4. 時刻情報を含む日付のフォーマット

時と分のオプションを追加して時刻コンポーネントを含めることで、日付と時刻の両方を1つのフォーマット済み文字列で表示します。

import { useIntl } from "react-intl";

export function AppointmentCard({ scheduledAt }: { scheduledAt: Date }) {
  const intl = useIntl();

  return (
    <div>
      <p>
        Scheduled for:{" "}
        {intl.formatDate(scheduledAt, {
          year: "numeric",
          month: "short",
          day: "numeric",
          hour: "numeric",
          minute: "2-digit",
        })}
      </p>
    </div>
  );
}

hourminuteオプションを追加すると、日付と時刻を組み合わせた文字列が生成されます。ロケールによって、12時間形式または24時間形式のどちらを使用するか、また日付と時刻の部分をどのように区切るかが決定されます。これにより、タイムスタンプの表示に関する地域の期待に沿った一貫性のあるフォーマットが維持されます。