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 メソッドは、日付表示にロケールの規則を適用します。オプションオブジェクトは、日付のどの部分を表示するか、およびその詳細レベルを制御します。フォーマットされた文字列は、コンポーネントツリーの上位にある 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>
        予定日時:{" "}
        {intl.formatDate(scheduledAt, {
          year: "numeric",
          month: "short",
          day: "numeric",
          hour: "numeric",
          minute: "2-digit",
        })}
      </p>
    </div>
  );
}

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