统一博客的时间格式

上一篇文章提到 day.js 这个库,并使用 dayjs/plugin/relativeTime 这个插件来实现几分钟前、几小时前、几天前这样的相对时间格式。

想使用相对时间格式是因为现在使用的 Artalk 评论,为了与之匹配,就想将博客显示时间的格式换成动态的相对时间。可当时没有观察仔细,后来回复空白评论时才注意到,原来 Artalk 评论的相对时间是有条件控制的。

搜索 Artalk 官方文档,看到一个配置项 dateFormatter 时间格式化函数发现超过 7 天就会显示具体日期,使用文档上的方法,的确可以使用 day.js 来进行配置。可当我查看 Artalk 源码时又有了新的想法,想要统一时间格式,好像也可以舍弃 day.js 直接使用 Artalk 的方案。

一、创建工具函数

// src/utils/relativeTime.ts
// 引用 Artalk 源码
// https://github.com/ArtalkJS/Artalk/blob/99736db27fab1d260423dc6d48f82778adb8c235/ui/artalk/src/lib/utils.ts#L61-L108

export function padWithZeros(vNumber: number, width: number) {
  let numAsString = vNumber.toString();
  while (numAsString.length < width) {
    numAsString = `0${numAsString}`;
  }
  return numAsString;
}

export function dateFormat(date: Date) {
  const vDay = padWithZeros(date.getDate(), 2);
  const vMonth = padWithZeros(date.getMonth() + 1, 2);
  const vYear = padWithZeros(date.getFullYear(), 2);
  return `${vYear}-${vMonth}-${vDay}`;
}

// 自定义 timeAgo,后续也可用回到 Artalk 上。
export function customTimeAgo(date: Date) {
  try {
    const oldTime = date.getTime();
    const currTime = new Date().getTime();
    const diffValue = currTime - oldTime;

    const days = Math.floor(diffValue / (24 * 3600 * 1000));
    if (days === 0) {
      const leave1 = diffValue % (24 * 3600 * 1000);
      const hours = Math.floor(leave1 / (3600 * 1000));
      if (hours === 0) {
        const leave2 = leave1 % (3600 * 1000);
        const minutes = Math.floor(leave2 / (60 * 1000));
        if (minutes === 0) {
          const leave3 = leave2 % (60 * 1000);
          const seconds = Math.round(leave3 / 1000);
          if (seconds < 10) return '刚刚';
          return `${seconds} 秒前`;
        }
        return `${minutes} 分钟前`;
      }
      return `${hours} 小时前`;
    }
    if (days < 0) return '刚刚';
    
    if (days < 8) {
      return `${days} 天前`;
    }
    
    return dateFormat(date);
  } catch (error) {
    console.error(error);
    return ' - ';
  }
}

// 更新相对时间函数
export const updateRelativeTimes = () => {
  const relativeTimeElements = document.querySelectorAll('.relative-time');
  const updateTime = () => {
    relativeTimeElements.forEach((element) => {
      const publishDate = element.getAttribute('data-publish-date');
      if (publishDate) {
        const publishDateObj = new Date(publishDate);
        element.textContent = customTimeAgo(publishDateObj);
      }
    });
  };

  setInterval(updateTime, 60000);
  updateTime();
};

二、接收工具函数

简单举例:

<p class="relative-time text-sm text-gray-600 dark:text-gray-400" data-publish-date={post.data.publishDate}>
	{post.data.publishDate}
</p>

<script>
  // 导入工具函数
  import { updateRelativeTimes } from '../utils/relativeTime';

  document.addEventListener('astro:page-load', () => {
    updateRelativeTimes();
  });
</script>

如此一来就将 Artalk 上的动态相对时间应用在博客上了,又进一步地压缩了 Astro 的打包体积,少了差不多 4 KB,哈哈哈。

三、扩展

  1. 如果感觉超过 7 天显示具体时间这个条件太短的话,可修改
if (days < 8) {
      return `${days} 天前`;
    }

// 简单举例
if (days < 60) {
   return days < 28 ? `${days} 天前` : '1 月前';
}
  1. 将工具函数中的 customTimeAgo 应用回 Artalk
import { customTimeAgo } from '../utils/relativeTime';

Artalk.init({
  // ... 其他配置
  dateFormatter: (date) => customTimeAgo(new Date(date)),
})

这样的话修改 customTimeAgo 的逻辑也能应用到 Artalk 中。