The exact issuance and expiry times in the device rows' hover titles were rendered in UTC, which reads as wrong to anyone not living there. - Mark the dates with a <time> element carrying the absolute (UTC) timestamp, rather than a custom data attribute whose name claimed to hold local time - Rewrite those titles in the browser's own zone, keeping the server's UTC rendering as the fallback for when JavaScript is unavailable - Only convert values that carry an explicit offset, so a date-only <time> is not read as UTC midnight and shifted onto the previous day - Give the revoke button a little more room from the device name and dates Part of #254
32 lines
1.0 KiB
JavaScript
32 lines
1.0 KiB
JavaScript
// Timestamps are rendered by the server in UTC, next to a <time> element's
|
|
// machine-readable value. Rewrite those elements' hover titles so they show the
|
|
// reader's own local time instead.
|
|
|
|
const LOCAL_TIME_FORMAT = new Intl.DateTimeFormat("en-GB", {
|
|
day: "numeric",
|
|
month: "short",
|
|
year: "numeric",
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
hourCycle: "h23",
|
|
})
|
|
|
|
// Only absolute timestamps carry a zone to convert from: a date-only value would
|
|
// be read as UTC midnight and shift to the previous day for most readers.
|
|
const ABSOLUTE_TIMESTAMP = /T\d{2}:\d{2}(:\d{2})?(\.\d+)?(Z|[+-]\d{2}:\d{2})$/
|
|
|
|
const localizeTimestamps = () => {
|
|
document.querySelectorAll("time[datetime]").forEach((element) => {
|
|
const value = element.getAttribute("datetime")
|
|
|
|
if (!ABSOLUTE_TIMESTAMP.test(value)) return
|
|
|
|
const timestamp = new Date(value)
|
|
|
|
if (!Number.isNaN(timestamp.getTime())) {
|
|
element.title = LOCAL_TIME_FORMAT.format(timestamp)
|
|
}
|
|
})
|
|
}
|
|
|
|
document.addEventListener("turbo:load", localizeTimestamps) |