size: 1 KiB

1window.addEventListener("load", () => {
2 enhanceTimeElements();
3});
4
5// Replace ISO datetime strings with momentjs-style relative text e.g. "20
6// minutes ago", "2 weeks ago"...
7function enhanceTimeElements() {
8 const millisecondsPerSecond = 1000;
9 const secondsPerMinute = 60;
10 const minutesPerHour = 60;
11 const hoursPerDay = 24;
12 const daysPerWeek = 7;
13 const daysPerMonth = 31;
14 const daysPerYear = 365; // getting imprecise here, but no big deal
15 const intervals = {
16 year:
17 millisecondsPerSecond *
18 secondsPerMinute *
19 minutesPerHour *
20 hoursPerDay *
21 daysPerYear,
22 month:
23 millisecondsPerSecond *
24 secondsPerMinute *
25 minutesPerHour *
26 hoursPerDay *
27 daysPerMonth,
28 week:
29 millisecondsPerSecond *
30 secondsPerMinute *
31 minutesPerHour *
32 hoursPerDay *
33 daysPerWeek,
34 day:
35 millisecondsPerSecond * secondsPerMinute * minutesPerHour * hoursPerDay,
36 hour: millisecondsPerSecond * secondsPerMinute * minutesPerHour,
37 minute: millisecondsPerSecond * secondsPerMinute,
38 second: millisecondsPerSecond,
39 };
40 const relativeDateFormat = new Intl.RelativeTimeFormat("en", {
41 style: "long",
42 });
43
44 // https://stackoverflow.com/a/78704662
45 function formatRelativeTime(isoStr) {
46 const diff = new Date(isoStr) - new Date();
47 for (const interval in intervals) {
48 if (intervals[interval] <= Math.abs(diff)) {
49 return relativeDateFormat.format(
50 Math.trunc(diff / intervals[interval]),
51 interval,
52 );
53 }
54 }
55 return relativeDateFormat.format(diff / 1000, "second");
56 }
57
58 document.querySelectorAll("time.relative").forEach((element) => {
59 const timeStr = element.getAttribute("datetime");
60 if (!timeStr) return;
61 const relativeTimeStr = formatRelativeTime(timeStr);
62 element.innerHTML = relativeTimeStr;
63 });
64}