如何以简短或完整形式显示相对时间

使用 style 选项控制相对时间显示为缩写、全称或紧凑符号

简介

当你显示诸如“2 小时前”或“3 个月后”这样的相对时间时,不同的格式会占用不同的空间。用于显示内容时效的时间戳可以是“2 小时前”、“2 小时.前”或“2h 前”,具体取决于你有多少空间以及需要多清晰。每种格式都在可读性和横向空间之间做出权衡。

不同的场景需要不同的格式选择。例如,社交媒体动态中的发布时间戳适合用“2 小时前”这样的清晰文本;移动端仪表盘上显示多个活动指示器时,则需要像“2h 前”这样紧凑的文本;数据可视化中的时间线事件则会采用最精简的形式,以便在屏幕上容纳更多信息。

JavaScript 的 Intl.RelativeTimeFormat 提供了 style 选项来控制这种显示方式。你可以选择长格式(完整拼写)、短格式(标准缩写)或窄格式(最紧凑的表示)。该选项让你可以精确控制相对时间在用户界面中的展示效果。

style 选项的作用

Intl.RelativeTimeFormat 中的 style 选项接受三个值:"long""short""narrow"。每个值都会生成不同详细程度的相对时间输出。

long 值会完整拼写出单词,如“2 小时前”;short 值会使用标准缩写,如“2 小时.前”;narrow 值则会生成最紧凑的表示,如“2h 前”,通常会去除空格并使用最少的符号。

const longFormatter = new Intl.RelativeTimeFormat("en-US", {
  style: "long"
});

console.log(longFormatter.format(-2, "hour"));
// Output: "2 hours ago"

const shortFormatter = new Intl.RelativeTimeFormat("en-US", {
  style: "short"
});

console.log(shortFormatter.format(-2, "hour"));
// Output: "2 hr. ago"

const narrowFormatter = new Intl.RelativeTimeFormat("en-US", {
  style: "narrow"
});

console.log(narrowFormatter.format(-2, "hour"));
// Output: "2h ago"

如果省略 style 选项,则默认为 "long"。这意味着相对时间格式化会使用完整的词语,除非你明确指定其他显示样式。

使用长格式显示相对时间

长格式会完整拼写每个词语。这种格式最大程度地保证了清晰度,但会占用更多的横向空间。

const formatter = new Intl.RelativeTimeFormat("en-US", {
  style: "long"
});

console.log(formatter.format(-2, "hour"));
// Output: "2 hours ago"

console.log(formatter.format(3, "day"));
// Output: "in 3 days"

格式化器会自动处理单数和复数形式。1 小时会用单数“hour”,多小时会用复数“hours”。你无需手动判断使用哪种形式。

const formatter = new Intl.RelativeTimeFormat("en-US", {
  style: "long"
});

console.log(formatter.format(-1, "hour"));
// Output: "1 hour ago"

console.log(formatter.format(-2, "hour"));
// Output: "2 hours ago"

console.log(formatter.format(1, "day"));
// Output: "in 1 day"

console.log(formatter.format(5, "day"));
// Output: "in 5 days"

无论使用哪个时间单位,都会完整拼写该单位的名称。

const formatter = new Intl.RelativeTimeFormat("en-US", {
  style: "long"
});

console.log(formatter.format(-30, "second"));
// Output: "30 seconds ago"

console.log(formatter.format(-5, "minute"));
// Output: "5 minutes ago"

console.log(formatter.format(-3, "month"));
// Output: "3 months ago"

console.log(formatter.format(2, "year"));
// Output: "in 2 years"

长格式让相对时间一目了然,无需用户去理解缩写。对于不熟悉时间缩写的用户,完整拼写的词语更易于理解。

使用短格式显示相对时间

短格式采用大多数人都能识别的标准缩写。这种格式在可读性和空间利用之间取得平衡。

const formatter = new Intl.RelativeTimeFormat("en-US", {
  style: "short"
});

console.log(formatter.format(-2, "hour"));
// Output: "2 hr. ago"

console.log(formatter.format(3, "day"));
// Output: "in 3 days"

格式化器会使用常见的标准缩写。小时为 "hr.",分钟为 "min.",秒为 "sec."。这些缩写在减少字符数量的同时保持了可读性。

const formatter = new Intl.RelativeTimeFormat("en-US", {
  style: "short"
});

console.log(formatter.format(-30, "second"));
// Output: "30 sec. ago"

console.log(formatter.format(-5, "minute"));
// Output: "5 min. ago"

console.log(formatter.format(-3, "month"));
// Output: "3 mo. ago"

console.log(formatter.format(2, "year"));
// Output: "in 2 yr."

每个时间单位都采用其标准缩写。秒用 "sec.",分钟用 "min.",月用 "mo.",年用 "yr."。这些缩写被广泛认可,适用于大多数场景。

你可以用短格式同时格式化过去和将来的时间。

const formatter = new Intl.RelativeTimeFormat("en-US", {
  style: "short"
});

console.log(formatter.format(-7, "day"));
// Output: "7 days ago"

console.log(formatter.format(2, "week"));
// Output: "in 2 wk."

console.log(formatter.format(-1, "quarter"));
// Output: "1 qtr. ago"

格式化器会一致地处理两个方向。过去的时间用“前”,将来的时间用“后”。缩写在不同方向下保持不变。

使用窄格式显示相对时间

窄格式提供最紧凑的表示方式。该格式会去除空格,并使用最少的符号,以最大限度地节省字符数。

const formatter = new Intl.RelativeTimeFormat("en-US", {
  style: "narrow"
});

console.log(formatter.format(-2, "hour"));
// Output: "2h ago"

console.log(formatter.format(3, "day"));
// Output: "in 3 days"

格式化器会对大多数单位采用单字母缩写和最小间距。例如,小时为 "h",分钟为 "m",秒为 "s"。输出比短格式或长格式更紧凑。

const formatter = new Intl.RelativeTimeFormat("en-US", {
  style: "narrow"
});

console.log(formatter.format(-30, "second"));
// Output: "30s ago"

console.log(formatter.format(-5, "minute"));
// Output: "5m ago"

console.log(formatter.format(-3, "month"));
// Output: "3mo ago"

console.log(formatter.format(2, "year"));
// Output: "in 2y"

窄格式会根据不同语言环境和单位而变化。有些单位的输出会明显更短,而有些则与短格式相似。英文中 "days" 仍然拼写完整,但小时、分钟和秒会缩写为单个字母。

const formatter = new Intl.RelativeTimeFormat("en-US", {
  style: "narrow"
});

console.log(formatter.format(-7, "day"));
// Output: "7 days ago"

console.log(formatter.format(2, "week"));
// Output: "in 2w"

console.log(formatter.format(-1, "quarter"));
// Output: "1q ago"

窄格式适用于空间极为有限且用户熟悉时间单位的场景。这种精简格式假设用户能够在没有明确分隔或说明的情况下理解各单位。

比较长格式、短格式和窄格式

当你用三种格式选项格式化相同的相对时间时,它们的区别会非常明显。

const longFormatter = new Intl.RelativeTimeFormat("en-US", {
  style: "long"
});

const shortFormatter = new Intl.RelativeTimeFormat("en-US", {
  style: "short"
});

const narrowFormatter = new Intl.RelativeTimeFormat("en-US", {
  style: "narrow"
});

const value = -2;
const unit = "hour";

console.log("Long:   " + longFormatter.format(value, unit));
console.log("Short:  " + shortFormatter.format(value, unit));
console.log("Narrow: " + narrowFormatter.format(value, unit));

// Output:
// Long:   2 hours ago
// Short:  2 hr. ago
// Narrow: 2h ago

长格式使用完整单词和明确的空格。短格式采用标准缩写并带有句点。窄格式则用单字母和最小间距。这个变化过程展示了清晰度与空间效率之间的权衡。

你可以对比不同的相对时间值,了解每种格式如何处理不同的时间跨度。

const times = [
  { value: -30, unit: "second" },
  { value: -5, unit: "minute" },
  { value: -2, unit: "hour" },
  { value: 3, unit: "day" },
  { value: 2, unit: "week" },
  { value: -3, unit: "month" }
];

times.forEach(time => {
  const long = new Intl.RelativeTimeFormat("en-US", {
    style: "long"
  }).format(time.value, time.unit);

  const short = new Intl.RelativeTimeFormat("en-US", {
    style: "short"
  }).format(time.value, time.unit);

  const narrow = new Intl.RelativeTimeFormat("en-US", {
    style: "narrow"
  }).format(time.value, time.unit);

  console.log(`${time.value} ${time.unit}:`);
  console.log(`  Long:   ${long}`);
  console.log(`  Short:  ${short}`);
  console.log(`  Narrow: ${narrow}`);
  console.log("");
});

// Output:
// -30 second:
//   Long:   30 seconds ago
//   Short:  30 sec. ago
//   Narrow: 30s ago
//
// -5 minute:
//   Long:   5 minutes ago
//   Short:  5 min. ago
//   Narrow: 5m ago
//
// -2 hour:
//   Long:   2 hours ago
//   Short:  2 hr. ago
//   Narrow: 2h ago
//
// 3 day:
//   Long:   in 3 days
//   Short:  in 3 days
//   Narrow: in 3 days
//
// 2 week:
//   Long:   in 2 weeks
//   Short:  in 2 wk.
//   Narrow: in 2w
//
// -3 month:
//   Long:   3 months ago
//   Short:  3 mo. ago
//   Narrow: 3mo ago

在多个时间戳中,字符数的差异会变得非常明显。在展示大量相对时间的列表或信息流中,窄格式相比长格式能显著节省横向空间。

不同语言下相对时间格式的差异

三种格式选项都会根据你指定的语言环境进行适配。不同语言会采用不同的缩写、用词和间距规范。

const locales = ["en-US", "de-DE", "fr-FR", "ja-JP"];

const value = -2;
const unit = "hour";

locales.forEach(locale => {
  const longFormatter = new Intl.RelativeTimeFormat(locale, {
    style: "long"
  });

  const shortFormatter = new Intl.RelativeTimeFormat(locale, {
    style: "short"
  });

  console.log(locale + ":");
  console.log("  Long:  " + longFormatter.format(value, unit));
  console.log("  Short: " + shortFormatter.format(value, unit));
});

// Output:
// en-US:
//   Long:  2 hours ago
//   Short: 2 hr. ago
// de-DE:
//   Long:  vor 2 Stunden
//   Short: vor 2 Std.
// fr-FR:
//   Long:  il y a 2 heures
//   Short: il y a 2 h
// ja-JP:
//   Long:  2 時間前
//   Short: 2 時間前

长格式在不同语言环境下差异显著,因为每种语言对时间单位有各自的表达方式和词序。例如,德语在时间数值前加 "vor",法语用 "il y a" 放在数值前,而日语则将时间指示词放在数字后。格式化工具会自动处理这些词序差异。

短格式同样会根据本地习惯进行调整。例如,德语用 "Std." 表示小时,法语用 "h",日语则与长格式相同。这些本地化缩写反映了各文化在简写相对时间时的习惯。

格式化工具会自动处理语法变化。每种语言环境下都能生成自然的输出结果。

const locales = ["en-US", "es-ES", "pt-BR"];

const value = -3;
const unit = "month";

locales.forEach(locale => {
  const narrowFormatter = new Intl.RelativeTimeFormat(locale, {
    style: "narrow"
  });

  console.log(locale + ": " + narrowFormatter.format(value, unit));
});

// Output:
// en-US: 3mo ago
// es-ES: hace 3 m
// pt-BR: há 3 meses

窄格式在不同语言环境下也有差异。英语用 "mo" 表示月份,西班牙语用 "m",葡萄牙语则拼写为 "meses"。这些差异体现了各地在紧凑时间标记上的本地化习惯。

何时使用长格式

当清晰度和可访问性比空间效率更重要时,长格式是最佳选择。这种方式让相对时间无需解释即可被直接理解。

以可访问性为重点的界面适合使用长格式,因为屏幕阅读器朗读完整单词更自然。例如,朗读“2 小时前”比“2 小时. 前”更流畅,无需特殊发音规则。

教育内容适合使用长格式,因为学习者可能不熟悉时间缩写。用于讲解时间戳的教材应完整拼写单位,以避免混淆。

活动流和时间线常用长格式,以保持清晰、对话式的语气。例如,社交媒体帖子显示“3 小时前”比“3h 前”在连贯文本中更自然。

正式报告和文档通常采用全称格式,以保持一致的书写标准。业务报告、审计日志和官方文件通常会将相对时间完整拼写出来,而不是使用缩写。

当用户可能正在学习语言时,国际用户更适合使用全称格式。像“小时”“天”这样的拼写单位名称比缩写更容易让非母语用户理解。

function formatActivityTimestamp(date, locale) {
  const formatter = new Intl.RelativeTimeFormat(locale, {
    style: "long",
    numeric: "auto"
  });

  const now = new Date();
  const diffInMs = date - now;
  const diffInHours = Math.round(diffInMs / (1000 * 60 * 60));

  return formatter.format(diffInHours, "hour");
}

const threeHoursAgo = new Date(Date.now() - 3 * 60 * 60 * 1000);

console.log("Activity: " + formatActivityTimestamp(threeHoursAgo, "en-US"));
// Output: "Activity: 3 hours ago"

全称格式优先考虑易读性而非简洁性。只要用户需要毫无歧义地理解相对时间,就应使用全称格式,避免任何解释上的困难。

何时使用简写格式

在空间有限但缩写广泛被理解的场景下,简写格式效果最佳。这种格式在清晰度和效率之间取得平衡。

移动端界面适合使用简写格式,因为屏幕宽度有限。仪表盘卡片显示多个时间戳时,需要紧凑的相对时间以适应屏幕信息。例如用“2 小时前”代替“2 小时之前”,可以为每个时间戳节省字符,累计下来节省空间。

评论区使用简写格式可以在不让界面杂乱的情况下显示评论发布时间。在评论旁显示“5 分钟前”比“5 分钟之前”更简洁,同时依然清晰易懂。

数据表格在列中显示时间戳时需要保持列宽一致。像“小时”“分钟”“秒”这样的简写可以让列宽更易控制,而“小时”“分钟”“秒钟”等全称会让列变宽,影响排版。

通知面板采用简写格式,因为用户在查看通知时对时间缩写已经很熟悉。显示“1 小时前”的通知可以兼顾清晰度和显示空间的高效利用。

邮件客户端使用简写格式显示邮件时间。在邮件列表中显示“2 天前”比“2d 前”更清楚,同时比完全拼写“2 天之前”更简洁。

function formatCommentTimestamp(date, locale) {
  const formatter = new Intl.RelativeTimeFormat(locale, {
    style: "short",
    numeric: "auto"
  });

  const now = new Date();
  const diffInMs = date - now;
  const diffInMinutes = Math.round(diffInMs / (1000 * 60));

  return formatter.format(diffInMinutes, "minute");
}

const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);

console.log(formatCommentTimestamp(fiveMinutesAgo, "en-US"));
// Output: "5 min. ago"

短格式在清晰度与高效性之间取得了平衡。大多数用户都能识别标准缩写,不会产生困惑。

何时使用窄格式

窄格式最适用于极度受空间限制的场景,此时每个字符都很重要,并且用户对时间表示法非常熟悉。

显示单一指标的紧凑型小部件在显示空间极小的情况下可以使用窄格式。例如,计时器小部件以小字体显示“5m 前”比“5 分钟前”更合适。

信息密集型数据可视化场景适合使用窄格式。图表标签、图形注释和时间线标记都需要尽量简短的文本,以避免遮挡底层的可视内容。对于了解上下文的用户来说,使用“2h 前”而不是“2 hr. 前”可以节省字符,同时保持可读性。

移动主屏幕小部件空间有限时,采用窄格式可以最大化信息密度。例如,活动追踪小部件在小方块中显示多个最近事件时,使用紧凑的相对时间表示法更有优势。

智能手表界面由于屏幕空间极其有限,通常采用窄格式。在小型圆形屏幕上显示“1h 前”比使用更长的格式效果更好。

在显示大量带有时间戳的项目的列表视图中,窄格式有助于保持每一行的紧凑。例如,音乐应用显示最近播放的曲目、视频应用显示观看历史或健身应用显示锻炼记录时,最小化时间戳格式都很有帮助。

function formatCompactTimestamp(date, locale) {
  const formatter = new Intl.RelativeTimeFormat(locale, {
    style: "narrow",
    numeric: "auto"
  });

  const now = new Date();
  const diffInMs = date - now;
  const diffInHours = Math.round(diffInMs / (1000 * 60 * 60));

  return formatter.format(diffInHours, "hour");
}

const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000);

console.log(formatCompactTimestamp(twoHoursAgo, "en-US"));
// Output: "2h ago"

窄格式假设用户熟悉时间表示法,并能无需辅助理解单位。这种选项以牺牲清晰度为代价,换取最大空间利用率。

将样式与 numeric 选项结合使用

style 选项可与 numeric 选项配合使用。numeric 选项控制输出是自然语言(如“昨天”)还是数值型(如“1 天前”)。style 选项则控制数值型输出出现时的详细程度。

const autoLong = new Intl.RelativeTimeFormat("en-US", {
  numeric: "auto",
  style: "long"
});

console.log(autoLong.format(-1, "day"));
// Output: "yesterday"

console.log(autoLong.format(-2, "day"));
// Output: "2 days ago"

const autoShort = new Intl.RelativeTimeFormat("en-US", {
  numeric: "auto",
  style: "short"
});

console.log(autoShort.format(-1, "day"));
// Output: "yesterday"

console.log(autoShort.format(-2, "day"));
// Output: "2 days ago"

numeric"auto" 且格式化器使用诸如“昨天”这样的自然语言时,style 选项不会生效,因为没有数字输出可供设置样式。无论样式如何,格式化器输出都相同。

当格式化器输出数字时,style 选项用于控制详细程度。

const alwaysLong = new Intl.RelativeTimeFormat("en-US", {
  numeric: "always",
  style: "long"
});

console.log(alwaysLong.format(-1, "day"));
// Output: "1 day ago"

const alwaysShort = new Intl.RelativeTimeFormat("en-US", {
  numeric: "always",
  style: "short"
});

console.log(alwaysShort.format(-1, "day"));
// Output: "1 day ago"

const alwaysNarrow = new Intl.RelativeTimeFormat("en-US", {
  numeric: "always",
  style: "narrow"
});

console.log(alwaysNarrow.format(-1, "day"));
// Output: "1 day ago"

对于天数,三种样式在英文中输出相似。不同的时间单位下,样式差异会更明显。

const alwaysLong = new Intl.RelativeTimeFormat("en-US", {
  numeric: "always",
  style: "long"
});

const alwaysShort = new Intl.RelativeTimeFormat("en-US", {
  numeric: "always",
  style: "short"
});

const alwaysNarrow = new Intl.RelativeTimeFormat("en-US", {
  numeric: "always",
  style: "narrow"
});

console.log("Long:   " + alwaysLong.format(-2, "hour"));
console.log("Short:  " + alwaysShort.format(-2, "hour"));
console.log("Narrow: " + alwaysNarrow.format(-2, "hour"));

// Output:
// Long:   2 hours ago
// Short:  2 hr. ago
// Narrow: 2h ago

这种组合让你可以完全控制是否使用自然语言以及数字输出的显示方式。

需要记住的要点

style 选项用于控制使用 Intl.RelativeTimeFormat 格式化时相对时间的显示方式。将其设置为 "long" 可获得如“2 小时前”这样的全拼形式,设置为 "short" 可获得如“2 小时前”的标准缩写,设置为 "narrow" 可获得如“2h 前”的紧凑形式。如果未设置,该选项默认为 "long"

当清晰度和可访问性比空间更重要,或用户可能不熟悉时间缩写时,请使用长样式。对于空间有限且用户了解标准缩写的通用应用,使用短样式。仅在极度空间受限且用户非常熟悉时间表示法的场景下使用窄样式。

格式化器会自动处理特定于本地的差异,包括不同的词语、缩写、词序和间距规范。将 stylenumeric 选项结合使用,可同时控制是否使用自然语言以及数字输出的显示方式。