Support Discord @time
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
// @ts-check
|
||||
|
||||
const assert = require("assert").strict
|
||||
|
||||
/*
|
||||
https://docs.discord.com/developers/reference#message-formatting
|
||||
|
||||
Trying to make these formats fairly culture independent since the Matrix text will show up the same for everyone.
|
||||
That means no ambiguous short dates like 03/04/26. The shortest allowable date is "medium", which spells the month.
|
||||
It also means no 24-hour time, since this is ambiguous to 12-hour time users. Times must have am/pm.
|
||||
Relative time is not supported for text conversion and will fall back to the default, "f".
|
||||
|
||||
See the test file for sample outputs.
|
||||
*/
|
||||
|
||||
/** @type {Map<string, Intl.DateTimeFormatOptions>} discord style letter abbreviation -> Intl.DateTimeFormat constructor options */
|
||||
const styles = new Map([
|
||||
["t", {timeStyle: "short", timeZone: "UTC"}],
|
||||
["T", {timeStyle: "medium", timeZone: "UTC"}],
|
||||
["d", {dateStyle: "medium", timeZone: "UTC"}],
|
||||
["D", {dateStyle: "long", timeZone: "UTC"}],
|
||||
["f", {dateStyle: "long", timeStyle: "short", timeZone: "UTC"}],
|
||||
["F", {dateStyle: "full", timeStyle: "short", timeZone: "UTC"}],
|
||||
["s", {dateStyle: "medium", timeStyle: "short", timeZone: "UTC"}],
|
||||
["S", {dateStyle: "medium", timeStyle: "medium", timeZone: "UTC"}]
|
||||
])
|
||||
const defaultStyle = "f"
|
||||
|
||||
/**
|
||||
* @param {string | null | undefined} [style]
|
||||
* @returns {Intl.DateTimeFormatOptions} */
|
||||
function getFormatOptions(style) {
|
||||
if (!style || !styles.has(style)) style = defaultStyle
|
||||
const formatOptions = styles.get(style)
|
||||
assert(formatOptions)
|
||||
return formatOptions
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} timestamp unix time in seconds
|
||||
* @param {string | null | undefined} [style] discord style letter abbreviation, if present
|
||||
* @returns {string}
|
||||
*/
|
||||
function convertDiscordTime(timestamp, style) {
|
||||
const formatter = new Intl.DateTimeFormat("en-NZ", getFormatOptions(style))
|
||||
const d = new Date(timestamp * 1000)
|
||||
return formatter.format(d) + " (UTC)"
|
||||
}
|
||||
|
||||
module.exports.getFormatOptions = getFormatOptions
|
||||
module.exports.convertDiscordTime = convertDiscordTime
|
||||
@@ -0,0 +1,48 @@
|
||||
// @ts-check
|
||||
|
||||
const time = require("./time")
|
||||
const {test} = require("supertape")
|
||||
|
||||
const d = new Date("2026-02-14T14:23:06.000Z")
|
||||
const seconds = d.getTime() / 1000
|
||||
|
||||
test("time: default style", t => {
|
||||
t.equal(time.convertDiscordTime(seconds), "14 February 2026 at 2:23 pm (UTC)")
|
||||
})
|
||||
|
||||
test("time: t style", t => {
|
||||
t.equal(time.convertDiscordTime(seconds, "t"), "2:23 pm (UTC)")
|
||||
})
|
||||
|
||||
test("time: T style", t => {
|
||||
t.equal(time.convertDiscordTime(seconds, "T"), "2:23:06 pm (UTC)")
|
||||
})
|
||||
|
||||
test("time: d style", t => {
|
||||
t.equal(time.convertDiscordTime(seconds, "d"), "14 Feb 2026 (UTC)")
|
||||
})
|
||||
|
||||
test("time: D style", t => {
|
||||
t.equal(time.convertDiscordTime(seconds, "D"), "14 February 2026 (UTC)")
|
||||
})
|
||||
|
||||
test("time: f style", t => {
|
||||
t.equal(time.convertDiscordTime(seconds, "f"), "14 February 2026 at 2:23 pm (UTC)")
|
||||
})
|
||||
|
||||
test("time: F style", t => {
|
||||
t.equal(time.convertDiscordTime(seconds, "F"), "Saturday, 14 February 2026 at 2:23 pm (UTC)")
|
||||
})
|
||||
|
||||
test("time: s style", t => {
|
||||
t.equal(time.convertDiscordTime(seconds, "s"), "14 Feb 2026, 2:23 pm (UTC)")
|
||||
})
|
||||
|
||||
test("time: S style", t => {
|
||||
t.equal(time.convertDiscordTime(seconds, "S"), "14 Feb 2026, 2:23:06 pm (UTC)")
|
||||
})
|
||||
|
||||
test("time: R style", t => {
|
||||
// Discord would display this as relative time, but I don't want to do that in a static message.
|
||||
t.equal(time.convertDiscordTime(seconds, "R"), "14 February 2026 at 2:23 pm (UTC)")
|
||||
})
|
||||
Reference in New Issue
Block a user