Skip to content

关于 Astro 时区的打开方式

更新于: at 17:34

内容目录

问题现象

在我书写第二篇文章时,Astro 首页的最新文章列表并未集成最新文章,而如果直接访问文章网址又可以正常显示,我稍作思考后感觉问题在于时区。

元数据发布时间的写法

在 Astro 支持的 Markdown 文件格式元数据中,有一个 pubDatetime 属性,此刻,电脑显示时间(自动同步时间服务器)是 2024-06-29 00:30:00,我处于 +08:00 的时区中。

为此文能在发布时正常显示,最简单的方式是,将时间转化为 UTC 格式(以Z结尾),于是,在我的时区,写为 2024-06-28T16:30:00Z。

这样做,Astro 会按 Web 服务器所在时区,向访问者显示本地时间。

虽然有一点小麻烦,也许也可以通过某些预处理来处理这个问题,但我相信这个自己换算时间的方式是最省事的,我称之为“最小代价全球化”。

更进一步:跨时区访问者

例如,处于 UTC+08:00 时区时,而服务器并不在此时区,那么访问者看到的时间也是不准确的,由于是静态托管,所以,对于“根据时区向访问者显示本地时间”这个需求,服务端无能为力,此时,我们依然需要客户端 JavaScript。

我的解决办法是在 Layout.astro 文件中添加处理代码,此处遵循了渐进增强(Progressive Enhancement)原则,还处理了 Datetime.tsx 组件中三个 span 标签中的 | 时间

    <script is:inline>
      document.addEventListener("DOMContentLoaded", () => {
        document
          .querySelectorAll("time[datetime]")
          .forEach(function (timeElement) {
            const utcTimeString = timeElement.getAttribute("datetime");
            const utcDate = new Date(utcTimeString);
            const localTimeString = utcDate.toLocaleString();
            timeElement.textContent = localTimeString;
            timeElement.textContent =
              localTimeString + " (UTC: " + utcTimeString + ")";

            let nextSibling = timeElement.nextElementSibling;
            for (let i = 0; i < 3 && nextSibling; i++) {
              if (nextSibling.tagName.toLowerCase() === "span") {
                nextSibling.parentNode.removeChild(nextSibling);
                nextSibling = timeElement.nextElementSibling;
              } else {
                break;
              }
            }
          });
      });
    </script>