内容目录
问题现象
在我书写第二篇文章时,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>