如何在 Next.js(Pages Router)v16 中为不同地区格式化日期

以地区特定的格式显示日期

问题

日期没有统一的书写格式。例如,10/12/2025 在美国表示 10 月 12 日,而在英国则表示 12 月 10 日。写作 "Oct 12, 2025" 假设了英文月份名称和特定的排列顺序。每个地区对日期格式都有自己的习惯,包括各部分的顺序、分隔符,以及月份是用文字还是数字表示。

如果只用单一格式显示日期,应用程序会让非该地区的用户感到陌生。用户可能会误解日期,或觉得难以阅读。对某些用户清晰明了的日期格式,对其他用户可能会造成困惑或歧义。

解决方案

根据用户的 locale 格式化日期,将日期值转换为符合地区规则的字符串,包括顺序、分隔符和月份名称。浏览器的 Intl.DateTimeFormat API 可以根据 locale 和可选的格式化参数,自动处理地区相关的日期格式规则。

react-intl 提供了封装该 API 的组件和 hooks,并与应用的 locale 上下文集成。通过将日期值和格式化选项传递给这些工具,日期会以用户语言和地区习惯的方式清晰自然地显示。

步骤

1. 使用 FormattedDate 创建日期格式化组件

FormattedDate 组件接受日期值和符合 Intl.DateTimeFormatOptions 的格式化选项。可以创建一个组件,以所需的详细程度显示日期。

import { FormattedDate } from "react-intl";

interface EventDateProps {
  date: Date;
}

export function EventDate({ date }: EventDateProps) {
  return (
    <time dateTime={date.toISOString()}>
      <FormattedDate value={date} year="numeric" month="long" day="numeric" />
    </time>
  );
}

FormattedDate 会从 IntlProvider 上下文中读取 locale,并相应地格式化日期。例如,en-US 会显示 "October 12, 2025",而 en-GB 会显示 "12 October 2025"。

2. 使用 useIntl 以命令式方式格式化日期

在无法使用 React 组件的场景(如设置文本属性)下,可以通过 useIntl hook 获取 formatDate 方法来格式化日期。

import { useIntl } from "react-intl";

interface ArticleImageProps {
  src: string;
  publishedAt: Date;
}

export function ArticleImage({ src, publishedAt }: ArticleImageProps) {
  const intl = useIntl();

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

  return <img src={src} alt={`Article published on ${formattedDate}`} />;
}

formatDate 方法会返回格式化后的日期字符串,并接受符合 DateTimeFormatOptions 的选项。此方法适用于属性、服务端代码或对性能要求较高的场景。

3. 通过标准选项调整格式化细节

可以通过指定 year、month、day 和 weekday 等选项,并设置为 "numeric"、"2-digit"、"long"、"short" 或 "narrow" 等值,来控制日期各部分的显示方式。

import { FormattedDate } from "react-intl";

export function FullEventDate({ date }: { date: Date }) {
  return (
    <FormattedDate
      value={date}
      weekday="long"
      year="numeric"
      month="long"
      day="numeric"
    />
  );
}

export function CompactDate({ date }: { date: Date }) {
  return (
    <FormattedDate value={date} year="2-digit" month="2-digit" day="2-digit" />
  );
}

FullEventDate 组件在 en-US 下会渲染为 "Monday, October 12, 2025",在 de-DE 下会渲染为 "Montag, 12. Oktober 2025"。CompactDate 组件则会生成适合表格或紧凑布局的简短数字格式。

4. 创建可复用的日期格式化辅助函数

为了在多个页面中保持日期格式一致,可以创建一个封装常用格式化模式的辅助函数。

import { useIntl } from "react-intl";

export function useDateFormatters() {
  const intl = useIntl();

  return {
    formatShortDate: (date: Date) =>
      intl.formatDate(date, {
        year: "numeric",
        month: "short",
        day: "numeric",
      }),

    formatLongDate: (date: Date) =>
      intl.formatDate(date, {
        weekday: "long",
        year: "numeric",
        month: "long",
        day: "numeric",
      }),

    formatMonthYear: (date: Date) =>
      intl.formatDate(date, {
        year: "numeric",
        month: "long",
      }),
  };
}

在任意页面组件中导入并使用该 hook,即可无需重复配置选项地实现一致的日期格式化。

5. 在页面组件中使用辅助函数

在 Next.js 页面中应用日期格式化辅助函数,以展示符合本地化的日期。

import { GetStaticProps } from "next";
import { useDateFormatters } from "../lib/useDateFormatters";

interface Post {
  title: string;
  publishedAt: string;
  content: string;
}

interface BlogPostPageProps {
  post: Post;
}

export default function BlogPostPage({ post }: BlogPostPageProps) {
  const { formatLongDate } = useDateFormatters();
  const publishedDate = new Date(post.publishedAt);

  return (
    <article>
      <h1>{post.title}</h1>
      <p>Published: {formatLongDate(publishedDate)}</p>
      <div>{post.content}</div>
    </article>
  );
}

export const getStaticProps: GetStaticProps = async () => {
  const post = {
    title: "Understanding Internationalization",
    publishedAt: "2025-10-12T00:00:00Z",
    content: "Content here...",
  };

  return {
    props: { post },
  };
};

页面会以用户本地格式显示发布日期,使各地区读者能够一目了然地理解日期信息。