如何按用户的区域设置格式化时间
使用 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 的显示方式也不同。英语使用 AM 和 PM,西班牙语使用 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"
这会创建一个用于美式英语的格式化器,显示小时和分钟。hour 和 minute 选项告诉格式化器包含这些组件。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 选项的工作方式与 hour 和 minute 相同。将其设置为 'numeric' 以在输出中包含秒。
使用 2-digit 控制数字填充
hour、minute 和 second 选项接受两个值:'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);
格式化后的字符串与其他字符串值一样。您可以将它们插入到文本内容、属性或任何其他向用户显示信息的上下文中。