如何显示 AM/PM 或本地化的日间时段
使用 JavaScript 显示符合各文化习惯的时间段
简介
当你显示像 4:00 这样的时间时,用户需要知道这是早上还是下午。在英语中,你会加上 AM 或 PM 以作区分。4:00 AM 表示日出前,4:00 PM 则是下午。
其他语言并不会简单地翻译 AM 和 PM。许多文化会将一天分为多个时段,并为清晨、上午、下午、傍晚和夜晚等设有专门的称呼。比如西班牙语中,“madrugada”指的是午夜后到黎明前的时段。德语则将一天分为六个不同的时段,而不是两个。有些语言会把凌晨 1 点称为“夜里 1 点”,而不是“早上 1 点”。
JavaScript 的 Intl.DateTimeFormat 提供 dayPeriod 选项,可以自动显示符合各地文化的时间段。本课将介绍各文化的日间时段划分方式、其对国际化应用的重要性,以及如何用合适的时段标签格式化时间。
为什么各地的日间时段不同
不同文化对 24 小时一天的划分方式各异,这些划分反映了人们对时间的理解和表达习惯。
英语使用者通常将一天分为四个时段:凌晨到中午为 morning,中午到傍晚为 afternoon,傍晚到天黑为 evening,天黑到午夜为 night。而 AM 和 PM 则为 12 小时制提供了更简单的两段式区分。
西班牙语使用者将 "madrugada" 视为一个独立的时间段,涵盖午夜后到人们通常起床前的时段。这种划分形成了五个时间段的系统,能够区分深夜和清晨。
俄语使用者用 "ночь"(夜晚)来指代人们通常在睡觉的所有时间。例如,凌晨 1 点被称为“夜里 1 点”,而不是“早上 1 点”,因为那时人们通常还在睡觉。
德语将一天分为六个时段:"Morgen"(早晨)、"Vormittag"(上午)、"Mittag"(中午)、"Nachmittag"(下午)、"Abend"(傍晚)、"Nacht"(夜晚),每个时段都对应特定的时间范围。
印尼语将一天分为四个时段:"pagi"(黎明至上午 10 点)、"siang"(上午 10 点至下午 2 点)、"sore"(下午 2 点至日落)、"malam"(夜晚),这些划分基于太阳的位置。
孟加拉语将一天分为六个时段:"ভোর"(黎明)、"সকাল"(早晨)、"দুপুর"(中午/早午)、"বিকাল"(下午/傍晚)、"সন্ধ্যা"(傍晚)、"রাত"(夜晚),每个时段都有明确的时间范围。
在国际化应用中显示时间时,需要使用符合各文化用户习惯的时间表达方式。如果对所有用户都显示 "4 AM",就忽略了其他语言对该时段的描述方式。
了解 dayPeriod 选项
dayPeriod 选项在 Intl.DateTimeFormat 中用于指示格式化器在显示时间时包含本地化的时段名称。格式化器不仅显示小时和分钟,还会根据目标语言添加对应的时段术语。
此选项仅适用于 12 小时时制。在 24 小时时制下,小时数字本身就足够提供时间上下文。例如,04:00 很明显是早晨,16:00 很明显是下午,无需额外标签。时段名称的存在是为了消除 12 小时时制下重复小时的歧义。
dayPeriod 选项接受三个值。narrow 会生成最简形式,通常是单个字母或缩写。short 会生成缩略形式。long 会生成完整的单词或短语。
对于许多本地化环境,这三个值会生成相同的输出。Unicode 本地化数据并未为每种语言环境和格式长度的组合定义不同的形式。当不存在不同形式时,格式化器会无论你指定哪个值都使用相同的输出。
使用日间时段格式化时间
要显示日间时段,请创建一个 Intl.DateTimeFormat 实例,并将 dayPeriod 选项设置为 narrow、short 或 long。你还需要包含一个时间组件选项,如 hour,并通过 hourCycle 指定 12 小时制。
const date = new Date('2025-01-15T04:30:00');
const formatter = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
});
console.log(formatter.format(date));
// Output: "4:30 in the morning"
这会创建一个显示小时、分钟和日间时段的格式化器。hourCycle: 'h12' 选项指定 12 小时制,这是显示日间时段所必需的。dayPeriod: 'long' 选项请求完整的日间时段短语。
如果没有 dayPeriod 选项,格式化器会显示 "4:30 AM"。日间时段选项会用更具描述性的短语替换简单的 AM/PM 指示。
在不同时间段显示日间时段
日间时段会根据所格式化的时间变化。格式化器会根据本地化环境的习惯自动选择合适的时段。
const options = {
hour: 'numeric',
minute: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
};
const formatter = new Intl.DateTimeFormat('en-US', options);
const morning = new Date('2025-01-15T04:30:00');
console.log(formatter.format(morning));
// Output: "4:30 in the morning"
const afternoon = new Date('2025-01-15T14:30:00');
console.log(formatter.format(afternoon));
// Output: "2:30 in the afternoon"
const evening = new Date('2025-01-15T20:30:00');
console.log(formatter.format(evening));
// Output: "8:30 in the evening"
const night = new Date('2025-01-15T23:30:00');
console.log(formatter.format(night));
// Output: "11:30 at night"
英语区分早晨、下午、傍晚和夜晚。每个时间点都会根据小时获得相应的短语。你无需判断适用哪个时段,格式化器会根据 Unicode 本地化数据自动处理。
比较窄格式、短格式和长格式
在某些本地化环境下,这三种格式长度会产生不同的输出。差异因语言而异,有时可能很细微,甚至不存在。
const date = new Date('2025-01-15T04:30:00');
const narrow = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
hourCycle: 'h12',
dayPeriod: 'narrow'
});
console.log(narrow.format(date));
// Output: "4 in the morning"
const short = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
hourCycle: 'h12',
dayPeriod: 'short'
});
console.log(short.format(date));
// Output: "4 in the morning"
const long = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
});
console.log(long.format(date));
// Output: "4 in the morning"
对于美国英语,三种长度的输出完全相同。该语言和时间组合的本地化数据未定义不同的格式。
有些本地化环境会区分不同的长度。例如,法语在窄格式和长格式下会有不同的输出。
const date = new Date('2025-01-15T04:30:00');
const frNarrow = new Intl.DateTimeFormat('fr-FR', {
hour: 'numeric',
hourCycle: 'h12',
dayPeriod: 'narrow'
});
console.log(frNarrow.format(date));
// Output: "4 mat."
const frLong = new Intl.DateTimeFormat('fr-FR', {
hour: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
});
console.log(frLong.format(date));
// Output: "4 du matin"
法语使用 "mat." 作为缩写形式,"du matin" 作为长格式。两者都表示早晨,但长格式更为明确。
除非有空间限制需要最短输出,否则建议使用 long 以获得更清晰的表达。长格式更易于用户理解,而且许多本地化环境本身并不提供更短的替代形式。
各地本地化环境中的日间时段处理方式
不同的本地化环境采用不同的日间时段术语,并在不同的时间点划分一天。格式化器会自动应用每个本地化环境的约定。
const date = new Date('2025-01-15T04:30:00');
const options = {
hour: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
};
const enUS = new Intl.DateTimeFormat('en-US', options);
console.log(enUS.format(date));
// Output: "4 in the morning"
const enGB = new Intl.DateTimeFormat('en-GB', options);
console.log(enGB.format(date));
// Output: "4 at night"
const deDK = new Intl.DateTimeFormat('de-DE', options);
console.log(deDK.format(date));
// Output: "4 morgens"
const fr = new Intl.DateTimeFormat('fr-FR', options);
console.log(fr.format(date));
// Output: "4 du matin"
英式英语将凌晨 4:30 视为“夜间”而不是“早晨”,这反映了不同文化对日间时段划分的差异。德语在早晨时段使用 "morgens",法语则用 "du matin"。
这些差异并非错误或不一致,而是反映了人们对时间概念和表达方式的真实文化差异。格式化器会根据本地化环境自动遵循这些差异。
日间时段需使用 12 小时制格式
dayPeriod 选项仅在你指定 hourCycle: 'h12' 或 hourCycle: 'h11' 以使用 12 小时制格式时有效。如果未使用 12 小时制,日间时段将不会显示。
const date = new Date('2025-01-15T04:30:00');
const with12Hour = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
});
console.log(with12Hour.format(date));
// Output: "4 in the morning"
const with24Hour = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
hourCycle: 'h23',
dayPeriod: 'long'
});
console.log(with24Hour.format(date));
// Output: "04"
24 小时制即使指定了时段选项,也不会显示昼夜时段。在 24 小时制中,小时数字本身已能提供足够的时间上下文,无需额外标签。
h12 和 h11 的区别在于午夜和中午的编号方式。标准 12 小时制(小时从 1 到 12)请使用 h12。0 到 11 小时制请使用 h11。两者都支持昼夜时段。
将昼夜时段与分钟和秒数结合
可以将分钟和秒数与昼夜时段一起显示。格式化器会根据本地习惯自动调整昼夜时段的位置。
const date = new Date('2025-01-15T04:30:45');
const withMinutes = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
});
console.log(withMinutes.format(date));
// Output: "4:30 in the morning"
const withSeconds = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
});
console.log(withSeconds.format(date));
// Output: "4:30:45 in the morning"
昼夜时段会显示在时间组件之后。无需手动调整昼夜时段的位置或格式,格式化器会根据本地习惯自动处理。
按用户本地习惯格式化带昼夜时段的时间
不要硬编码特定的语言环境,应使用浏览器中用户的首选语言。navigator.language 属性会返回用户的首选语言。
const date = new Date('2025-01-15T04:30:00');
const formatter = new Intl.DateTimeFormat(navigator.language, {
hour: 'numeric',
minute: 'numeric',
hourCycle: 'h12',
dayPeriod: 'long'
});
console.log(formatter.format(date));
// Output varies by user's locale
// For en-US: "4:30 in the morning"
// For en-GB: "4:30 at night"
// For de-DE: "4:30 morgens"
// For fr-FR: "4:30 du matin"
这种方式可以显示符合用户日常表达习惯的昼夜时段。浏览器提供语言偏好,Intl API 会自动应用合适的昼夜时段术语和分界。
何时使用昼夜时段
当你希望提供比简单 AM/PM 指示更丰富的时间上下文时,昼夜时段非常适用。它们让时间表达更口语化,也更易于快速理解。
在用户界面中,如果时间与描述性文本一起出现,建议使用昼夜时段。例如,日历中显示“凌晨 4:30”比“4:30 AM”更清晰,因为这种表达在连续文本中更自然。
在通知和消息中,建议使用日间时段表达,以便通过更口语化的语言提升可读性。例如,“您的会议将在晚上 8:30 开始”比“您的会议将在 8:30 PM 开始”更易理解。
在空间有限的紧凑显示中应避免使用日间时段表达。表格、图表和密集布局中,标准的 AM/PM 标识或 24 小时制更为合适。
在以 24 小时制显示时间时,应避免使用日间时段表达。此时,小时数字已能准确指示时间,日间时段信息无实际意义。
总结
dayPeriod 选项在 Intl.DateTimeFormat 中会显示与文化相关的时段术语。不同文化对一天的划分方式不同,例如西班牙语中的 "madrugada",或德语中将一天分为六个时段,而不仅仅是 AM 和 PM。
该选项接受三个取值。narrow 生成最简短的形式,short 生成缩略形式,long 生成完整短语。许多本地化环境下,这三种取值的输出可能相同。
仅在使用 hourCycle: 'h12' 或 hourCycle: 'h11' 指定 12 小时制时,才会显示日间时段。24 小时制下不会显示,因为小时数字已能提供足够的时间信息。
不同地区会采用不同的日间时段术语,并在不同的时间点划分时段。格式化器会根据本地标识自动应用这些约定。例如,英式英语将 4:30 AM 视为“夜间”,而美式英语则视为“清晨”。