如何按用户的区域设置格式化时间

使用 JavaScript 根据每个用户的区域习惯显示时间

介绍

世界各地的时间显示方式不同。美国人通常将下午 3:30 显示为 3:30 PM,而大多数欧洲人则期望看到 15:30。当您硬编码时间格式时,就假设了所有用户都遵循相同的惯例。

以不熟悉的格式显示时间会引起混淆。习惯于 24 小时制的用户看到 3:30 PM 时,必须在脑海中将其转换为上午或下午的时间。这种认知负担会在应用程序中的每个时间点上累积。

JavaScript 提供了 Intl.DateTimeFormat API 来自动处理时间格式化。本课程将解释为什么时间格式因文化而异、API 的工作原理以及如何为任何区域正确格式化时间。

为什么时间格式因区域而异

不同地区发展了不同的时间显示惯例。这些惯例反映了历史习惯、教育体系和文化偏好。没有一种格式是通用的。

在美国、加拿大、澳大利亚和菲律宾,时间使用带有 AM 和 PM 指示的 12 小时制。下午 3:30 显示为 3:30 PM

在大多数欧洲国家、拉丁美洲和亚洲,时间使用不带 AM 或 PM 指示的 24 小时制。同一时间显示为 15:30

小时和分钟之间的分隔符也有所不同。英语国家使用冒号,而某些地区使用句点或其他标点符号。

AM 和 PM 的显示方式也不同。英语使用 AMPM,西班牙语使用 a.m.p.m.,某些地区将这些指示符放在时间之前而不是之后。

当您显示时间时,需要匹配用户对小时格式和具体格式惯例的期望。

使用 Intl.DateTimeFormat 格式化时间

Intl.DateTimeFormat 构造函数创建一个格式化器,应用特定于区域的约定。要格式化时间,请将区域标识符作为第一个参数传递,并在第二个参数中指定与时间相关的选项。

const formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric'
});

const date = new Date('2025-03-15T15:30:00');
console.log(formatter.format(date));
// 输出: "3:30 PM"

这会创建一个用于美式英语的格式化器,显示小时和分钟。hourminute 选项告诉格式化器包含这些组件。format() 方法将 Date 对象转换为具有适当格式的字符串。

Date 构造函数接受一个 ISO 8601 日期时间字符串,例如 2025-03-15T15:30:00。这会创建一个表示 2025 年 3 月 15 日下午 3:30 的 Date 对象。然后,格式化器将其转换为特定于区域的时间字符串。

为不同区域格式化相同的时间

通过更改传递给构造函数的区域标识符,可以为不同的区域格式化相同的时间。

const date = new Date('2025-03-15T15:30:00');

const usFormatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric'
});
console.log(usFormatter.format(date));
// 输出: "3:30 PM"

const gbFormatter = new Intl.DateTimeFormat('en-GB', {
  hour: 'numeric',
  minute: 'numeric'
});
console.log(gbFormatter.format(date));
// 输出: "15:30"

const deFormatter = new Intl.DateTimeFormat('de-DE', {
  hour: 'numeric',
  minute: 'numeric'
});
console.log(deFormatter.format(date));
// 输出: "15:30"

const frFormatter = new Intl.DateTimeFormat('fr-FR', {
  hour: 'numeric',
  minute: 'numeric'
});
console.log(frFormatter.format(date));
// 输出: "15:30"

每个格式化器应用不同的约定。美国格式化器使用带有 AM/PM 的 12 小时制。英国、德国和法国的格式化器都使用不带 AM/PM 指示符的 24 小时制。

您无需了解每个区域使用的格式。API 会根据区域标识符自动处理这些细节。

在时间显示中包含秒

您可以添加 second 选项,以在显示小时和分钟的同时显示秒。

const formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
});

const date = new Date('2025-03-15T15:30:45');
console.log(formatter.format(date));
// 输出: "3:30:45 PM"

second 选项的工作方式与 hourminute 相同。将其设置为 'numeric' 以在输出中包含秒。

使用 2-digit 控制数字填充

hourminutesecond 选项接受两个值:'numeric''2-digit''numeric' 值显示不带填充的数字,而 '2-digit' 始终显示带有前导零的两位数字。

const date = new Date('2025-03-15T09:05:03');

const numericFormatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
});
console.log(numericFormatter.format(date));
// 输出: "9:05:03 AM"

const twoDigitFormatter = new Intl.DateTimeFormat('en-US', {
  hour: '2-digit',
  minute: '2-digit',
  second: '2-digit'
});
console.log(twoDigitFormatter.format(date));
// 输出: "09:05:03 AM"

数字格式化器显示 9:05:03 AM,小时为单个数字。两位数字格式化器显示 09:05:03 AM,小时带有前导零。由于这些值通常会被填充,无论设置如何,分钟和秒都显示为两位数字。

强制使用 12 小时或 24 小时格式

默认情况下,API 使用该语言环境首选的时间格式。您可以通过 hour12 选项覆盖此设置。

const date = new Date('2025-03-15T15:30:00');

const hour12Formatter = new Intl.DateTimeFormat('en-GB', {
  hour: 'numeric',
  minute: 'numeric',
  hour12: true
});
console.log(hour12Formatter.format(date));
// 输出: "3:30 pm"

const hour24Formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric',
  hour12: false
});
console.log(hour24Formatter.format(date));
// 输出: "15:30"

设置 hour12: true 强制使用 12 小时格式,即使对于通常使用 24 小时格式的语言环境也是如此。设置 hour12: false 强制使用 24 小时格式,即使对于通常使用 12 小时格式的语言环境也是如此。

语言环境仍然决定其他格式化细节,例如标点和间距。带有 hour12: true 的英国格式化器显示 3:30 pm,其中 pm 为小写,而美国格式化器会显示 3:30 PM,其中 PM 为大写。

为用户的语言环境格式化时间

与硬编码特定的语言环境不同,您可以使用浏览器中用户的首选语言。navigator.language 属性返回用户的首选语言。

const userLocale = navigator.language;
const formatter = new Intl.DateTimeFormat(userLocale, {
  hour: 'numeric',
  minute: 'numeric'
});

const date = new Date('2025-03-15T15:30:00');
console.log(formatter.format(date));
// 输出因用户的语言环境而异
// 对于 en-US: "3:30 PM"
// 对于 en-GB: "15:30"
// 对于 de-DE: "15:30"
// 对于 fr-FR: "15:30"

这种方法根据每个用户的期望显示时间,而无需用户手动选择语言环境。浏览器提供语言偏好,Intl API 应用适当的格式化约定。

您还可以传递整个首选语言数组以启用回退行为。

const formatter = new Intl.DateTimeFormat(navigator.languages, {
  hour: 'numeric',
  minute: 'numeric'
});

const date = new Date('2025-03-15T15:30:00');
console.log(formatter.format(date));

API 使用数组中支持的第一个语言环境。这在用户的首选语言不可用时提供了更好的回退处理。

创建用于格式化的时间

您可以通过多种方式创建包含时间信息的 Date 对象。最可靠的方法是使用 ISO 8601 日期时间字符串。

const time1 = new Date('2025-03-15T09:00:00');
const time2 = new Date('2025-03-15T15:30:00');
const time3 = new Date('2025-03-15T23:45:30');

const formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric'
});

console.log(formatter.format(time1));
// 输出: "9:00 AM"

console.log(formatter.format(time2));
// 输出: "3:30 PM"

console.log(formatter.format(time3));
// 输出: "11:45 PM"

ISO 8601 日期时间字符串使用 YYYY-MM-DDTHH:MM:SS 格式。T 用于分隔日期和时间。此格式明确且在所有语言环境和时区中都能一致工作。

从时间戳格式化时间

您还可以从 Unix 时间戳创建 Date 对象。Unix 时间戳表示自 1970 年 1 月 1 日 UTC 起的毫秒数。

const timestamp = 1710515400000; // 2025 年 3 月 15 日下午 3:30
const date = new Date(timestamp);

const formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric'
});
console.log(formatter.format(date));
// 输出: "3:30 PM"

当您从 API、数据库或其他以数字表示时间的系统接收时间戳时,此方法非常有效。

您还可以直接将时间戳传递给 format() 方法,而无需先创建 Date 对象。

const formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric'
});

const timestamp = 1710515400000;
console.log(formatter.format(timestamp));
// 输出: "3:30 PM"

该 API 同时接受 Date 对象和时间戳。根据您的代码需求选择适合的方法。

格式化当前时间

要格式化当前时间,可以创建一个不带参数的 Date 对象。这将创建一个表示当前时刻的 Date 对象。

const formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
});

const now = new Date();
console.log(formatter.format(now));
// 输出: "3:45:12 PM"(或运行时的当前时间)

您还可以直接传递 Date.now(),它会返回当前时间戳作为数字。

const formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
});

console.log(formatter.format(Date.now()));
// 输出: "3:45:12 PM"(或运行时的当前时间)

两种方法产生的结果是相同的。

重用格式化器以提高性能

创建一个新的 Intl.DateTimeFormat 实例需要加载区域设置数据并处理选项。当您需要使用相同的区域设置和设置格式化多个时间时,可以创建一次格式化器并重复使用它。

const formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric'
});

const times = [
  new Date('2025-03-15T09:00:00'),
  new Date('2025-03-15T12:30:00'),
  new Date('2025-03-15T18:45:00')
];

times.forEach(time => {
  console.log(formatter.format(time));
});
// 输出:
// "9:00 AM"
// "12:30 PM"
// "6:45 PM"

这种方法比为每个时间创建一个新的格式化器更高效。当格式化包含数百或数千个时间值的数组时,性能差异会变得显著。

在模板中格式化时间

您可以在任何向用户显示时间的地方使用 Intl.DateTimeFormat。这包括将格式化的时间插入到 HTML 模板中、在表格中显示时间或在用户界面中显示时间戳。

const formatter = new Intl.DateTimeFormat(navigator.language, {
  hour: 'numeric',
  minute: 'numeric'
});

const eventStart = new Date('2025-03-15T14:00:00');
const eventEnd = new Date('2025-03-15T16:30:00');

document.getElementById('start-time').textContent = formatter.format(eventStart);
document.getElementById('end-time').textContent = formatter.format(eventEnd);

格式化后的字符串与其他字符串值一样。您可以将它们插入到文本内容、属性或任何其他向用户显示信息的上下文中。