• 作者:老汪软件技巧
  • 发表时间:2024-09-25 10:01
  • 浏览量:

前言

Hello~ 大家好。我是秋天的一阵风~

在前端项目开发中,我们经常需要处理时间数据,尤其是在社交媒体、新闻网站或任何需要展示最新信息的平台上。这些场景下,直接显示具体的时间戳往往不够友好,用户更倾向于看到相对时间,比如“3小时前”、“昨天”或“一周前”。这种相对时间的表示方式可以让用户更直观地感受到信息的新旧程度,提升用户体验。

在日常开发中,我们可以选择以下几种方式来实现这个功能,接下来我们一一介绍~

一、手写实现

最简单粗暴的方式当然是“一把梭手写”了,以下是我自己封装的一个相对化时间工具函数:

function getTimeAgoDisplay(targetDate) {
        const now = new Date();
        const diff = now - targetDate; // 计算时间差,单位为毫秒
        const oneDay = 24 * 60 * 60 * 1000; // 一天的毫秒数
        const oneHour = 60 * 60 * 1000; // 一小时的毫秒数
        const oneMinute = 60 * 1000; // 一分钟的毫秒数
        const oneYear = 365 * 24 * 60 * 60 * 1000; // 一年的毫秒数
        const oneMonth = 30 * 24 * 60 * 60 * 1000; // 假设一个月为30天的毫秒数
        const twoDays = oneDay * 2;
        if (diff < oneMinute) {
          return "刚刚";
        } else if (diff < oneHour) {
          return Math.round(diff / oneMinute) + "分钟前";
        } else if (diff < oneDay) {
          return Math.round(diff / oneHour) + "小时前";
        } else if (diff < twoDays) {
          return "昨天";
        } else if (diff < oneMonth) {
          const days = Math.round(diff / oneDay);
          return days + "天前";
        } else if (diff < oneYear) {
          const months = Math.round(diff / oneMonth);
          return months + "个月前";
        } else {
          const years = Math.round(diff / oneYear);
          return years + "年前";
        }
      }
      // 使用示例
      console.log(
        "2024-09-23T22:42:00 ",
        getTimeAgoDisplay(new Date("2024-09-23T22:42:00"))
      );
      console.log(
        "2024-09-23T22:00:00 ",
        getTimeAgoDisplay(new Date("2024-09-23T22:00:00"))
      );
      console.log(
        "2024-09-23T21:00:00 ",
        getTimeAgoDisplay(new Date("2024-09-23T21:00:00"))
      );
      console.log(
        "2024-09-22T22:00:00 ",
        getTimeAgoDisplay(new Date("2024-09-22T22:00:00"))
      );
      console.log(
        "2024-09-21T22:00:00 ",
        getTimeAgoDisplay(new Date("2024-09-21T22:00:00"))
      );
      console.log(
        "2024-09-07T12:00:00 ",
        getTimeAgoDisplay(new Date("2024-09-07T12:00:00"))
      );
      console.log(
        "2023-09-07T12:00:00 ",
        getTimeAgoDisplay(new Date("2023-09-07T12:00:00"))
      );

二、dayjs实现

当然,嫌麻烦的同学也可以直接借助一些第三方的时间插件来实现,比如 。具体的使用方法我们在这里就不在赘述了,官网里有非常详细的使用案例。


dayjs.extend(relativeTime)
dayjs('1999-01-01').fromNow() // 22 年前
var a = dayjs('2000-01-01')
dayjs('1999-01-01').from(a) // 1 年前
dayjs('1999-01-01').toNow() // 22 年后

三、内置对象 Intl.RelativeTimeFormat实现

上面两种实现方法其实都有一个缺点,就是对国际化的支持并不友好。这也引出了本篇文章的重点,如何实现时间相对化还要支持国际化呢?其实呀,原生javascript就内置了一个Intl.RelativeTimeFormat对象,帮助我们轻松实现相对时间国际化。

1. 什么是 Intl.RelativeTimeFormat?

Intl.RelativeTimeFormat是 ECMAScript 国际化 API 中的一个构造函数,用于格式化相对于当前时间的时间段。它支持多种语言和区域设置,使得国际化和本地化变得更加容易

2. 基本用法

要使用 Intl.RelativeTimeFormat,你首先需要创建一个新的实例,指定所需的语言和选项。然后,你可以使用这个实例来格式化时间差。

      const cnFormat = new Intl.RelativeTimeFormat("zh");
      const enFormat = new Intl.RelativeTimeFormat("en");
      console.log(cnFormat.format(-1, "day")); // 1天前
      console.log(enFormat.format(-1, "day")); // 1 day ago
      console.log(cnFormat.format(1, "day"));  // 1天后
      console.log(enFormat.format(1, "day"));  // in 1 day 
      console.log(cnFormat.format(3, "quarter")); // 3个季度后
      console.log(enFormat.format(3, "quarter")); // in 3 quarters

这里构造函数的第一个参数是指定语言,'zh-CN' 指定了使用简体中文。'en' 指定了使用英文。

冷知识!原生Javascript竟然也能实现时间相对化!还支持国际化!!!__冷知识!原生Javascript竟然也能实现时间相对化!还支持国际化!!!

format的第二参数则是指定时间单位,Intl.RelativeTimeFormat支持多种时间单位,包括:

      console.log(cnFormat.format(-1, "second")); // 1秒钟前
      console.log(cnFormat.format(5, "minute")); // 5分钟后
      console.log(cnFormat.format(-3, "hour")); // 3小时前
      console.log(cnFormat.format(1, "day")); // 1天后
      console.log(cnFormat.format(-1, "week")); // 1周前
      console.log(cnFormat.format(2, "month")); // 2个月后
      console.log(cnFormat.format(-1, "year")); // 1年前

3. 自定义配置对象 options

Intl.RelativeTimeFormat还支持传入第二个参数,可选的自定义配置对象。它包含以下几个属性:

(1) localeMatcher:

用于匹配区域设置的算法。可能的值有 "lookup" 和 "best fit";默认值是 "best fit"。

这其实是跟内部查找算法有关:

Two matching algorithms exist: the "lookup" matcher follows the Lookup algorithm specified in BCP 47; the "best fit" matcher lets the runtime provide a locale that's at least, but possibly more, suited for the request than the result of the Lookup algorithm. If the application doesn't provide a locales argument, or the runtime doesn't have a locale that matches the request, then the runtime's default locale is used. The matcher can be selected using a property of the options argument (see below).

(2) numberingSystem

用于数字格式化的编号系统,例如 "arab"(阿拉伯数字)、"hans"(汉字数字)、"mathsans" 等。支持的编号系统类型列表,请参见 Intl.Locale.prototype.getNumberingSystems()。此选项也可以通过nu Unicode 扩展键设置;如果同时提供了这两个选项,此属性将优先。

(3) style

格式化相对时间的样式。可能的值有:

-   "long"(默认):例如,“1个月后”
-   "short":例如,“1个月”
-   "narrow":例如,“1个月”。narrow 样式对于某些区域设置可能与 short 样式相似。

(4) numeric

输出中是否使用数字值。可能的值有 "always" 和 "auto";默认值是 "always"。

当设置为 "auto" 时,输出可能使用更符合习惯的措辞,例如使用 "昨天" 而不是 "1天前"。

举个例子:

      const cnFormat = new Intl.RelativeTimeFormat("zh");
      console.log(cnFormat.format(-1, "day")); // 1天前
      const cnFormat1 = new Intl.RelativeTimeFormat("zh", { numeric: "auto" });
      console.log(cnFormat1.format(-1, "day")); // 昨天

四、总结

Intl RelativeFormat 是一个强大的工具,它可以帮助你在编程中生成相对时间的字符串。无论你的应用程序需要支持哪种语言环境,Intl RelativeFormat 都可以帮助你生成符合当地习惯的相对时间字符串。希望这篇文章能帮助你更好地理解 Intl RelativeFormat 及其在字符串日期时间转换中的应用。