feat: more readable time delta #193

Merged
Anri merged 6 commits from date into dev 2024-10-08 20:53:29 +02:00
5 changed files with 74 additions and 20 deletions

View file

@ -1,4 +1,10 @@
import { nextTimeUnit, showDate, strToSeconds, TimeSecond } from "../../utils/time"; import {
nextTimeUnit,
showDate,
strToSeconds,
timeDeltaToString,
TimeSecond,
} from "../../utils/time";
describe("Date with correct timezone", () => { describe("Date with correct timezone", () => {
const map = new Map([["u_time_at", "@"]]); const map = new Map([["u_time_at", "@"]]);
@ -84,3 +90,25 @@ describe("Next time unit", () => {
}); });
} }
}); });
describe("Relative time", () => {
// Thoses tests are based on time, we have 10s of acceptance.
{
const name = Date.now() + (10 * TimeSecond.Minute + 30) * 1000;
test(name.toString(), () => {
expect(timeDeltaToString(name)).toMatch(/10m 30s|10m 2\ds/);
});
}
{
const name = Date.now() + (12 * TimeSecond.Hour + 30 * TimeSecond.Minute) * 1000;
test(name.toString(), () => {
expect(timeDeltaToString(name)).toMatch(/12h 30m|12h 29m 5\ds/);
});
}
{
const name = Date.now() + (TimeSecond.Week + TimeSecond.Day + 6 * TimeSecond.Hour) * 1000;
test(name.toString(), () => {
expect(timeDeltaToString(name)).toMatch(/1w 1d 6h|1w 1d 5h 59m 5\ds/);
});
}
});

View file

@ -131,3 +131,8 @@ export const emojiPng = (emoji: string) =>
`https://cdn.jsdelivr.net/gh/twitter/twemoji/assets/72x72/${emoji `https://cdn.jsdelivr.net/gh/twitter/twemoji/assets/72x72/${emoji
.codePointAt(0) .codePointAt(0)
?.toString(16)}.png`; ?.toString(16)}.png`;
/**
* Blank character
*/
export const blank = "\u200b";

View file

@ -2,6 +2,7 @@ import { EmbedBuilder } from "@discordjs/builders";
import { GuildQueue, QueueRepeatMode } from "discord-player"; import { GuildQueue, QueueRepeatMode } from "discord-player";
import { Client } from "discord.js"; import { Client } from "discord.js";
import { getLocale } from "./locales"; import { getLocale } from "./locales";
import { blank } from "./misc";
export const embedListQueue = ( export const embedListQueue = (
client: Client, client: Client,
@ -30,7 +31,7 @@ export const embedListQueue = (
? loc.get("c_queue10") ? loc.get("c_queue10")
: (idx === 1 && page === 1) || (idx === 0 && page > 1) : (idx === 1 && page === 1) || (idx === 0 && page > 1)
? loc.get("c_queue11") ? loc.get("c_queue11")
: "\u200b"; : blank;
const idx_track = now_playing ? "" : `${idx + limit_fields * (page - 1)}. `; const idx_track = now_playing ? "" : `${idx + limit_fields * (page - 1)}. `;
embed.addFields({ embed.addFields({
name, name,

View file

@ -1,6 +1,6 @@
import { Client, Colors, EmbedBuilder, User } from "discord.js"; import { Client, Colors, EmbedBuilder, User } from "discord.js";
import { getLocale } from "./locales"; import { getLocale } from "./locales";
import { cleanCodeBlock } from "./misc"; import { blank, cleanCodeBlock } from "./misc";
import { showDate, strToSeconds, timeDeltaToString } from "./time"; import { showDate, strToSeconds, timeDeltaToString } from "./time";
import { RegexC, RegExpFlags } from "./regex"; import { RegexC, RegExpFlags } from "./regex";
@ -88,6 +88,8 @@ export const newReminder = async (client: Client, time: string, info: infoRemind
const timeoutId = setTimeoutReminder(client, info, data.option, timeout); const timeoutId = setTimeoutReminder(client, info, data.option, timeout);
const expiration_date = info.createdAt + timeout * 1000;
// Add the remind to the db // Add the remind to the db
client.db.run( client.db.run(
"INSERT INTO reminder ( \ "INSERT INTO reminder ( \
@ -95,7 +97,7 @@ export const newReminder = async (client: Client, time: string, info: infoRemind
) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? );", ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? );",
[ [
info.message, info.message,
`${info.createdAt + timeout * 1000}`, `${expiration_date}`,
data.option.valueOf(), data.option.valueOf(),
info.channelId, info.channelId,
`${info.createdAt}`, `${info.createdAt}`,
@ -110,7 +112,7 @@ export const newReminder = async (client: Client, time: string, info: infoRemind
} }
// Send confirmation to user // Send confirmation to user
ok(`${loc.get("c_reminder1")} ${data.time}.`); ok(`${loc.get("c_reminder1")} ${timeDeltaToString(expiration_date)}.`);
}, },
); );
}); });
@ -440,7 +442,7 @@ export const embedListReminders = async (
}); });
} else { } else {
embed.addFields({ embed.addFields({
name: "\u200b", name: blank,
value: `${loc.get("c_reminder10")}${page} ${loc.get("c_reminder11")}.`, value: `${loc.get("c_reminder10")}${page} ${loc.get("c_reminder11")}.`,
}); });
} }

View file

@ -3,15 +3,15 @@ import { RegexC, RegExpFlags } from "./regex";
/** /**
* Parsed string adapted with TZ (locales) and format for the specified lang * Parsed string adapted with TZ (locales) and format for the specified lang
* @param tz Lang * @param lang Locale
* @param locale Locales * @param translation Translation for "at"
* @param date Date * @param date Date
* @returns String * @returns String
*/ */
export const showDate = (tz: string, locale: Map<string, unknown>, date: Date) => { export const showDate = (lang: string, translation: Map<string, unknown>, date: Date) => {
const localeInfo = new Intl.Locale(tz); const localeInfo = new Intl.Locale(lang);
const intlTimezone = moment.tz.zonesForCountry(localeInfo.region ?? localeInfo.baseName); const intlTimezone = moment.tz.zonesForCountry(localeInfo.region ?? localeInfo.baseName);
const formattedDate = new Intl.DateTimeFormat(tz, { const formattedDate = new Intl.DateTimeFormat(lang, {
timeZone: intlTimezone ? intlTimezone[0] : "Factory", timeZone: intlTimezone ? intlTimezone[0] : "Factory",
dateStyle: "short", dateStyle: "short",
timeStyle: "medium", timeStyle: "medium",
@ -19,14 +19,14 @@ export const showDate = (tz: string, locale: Map<string, unknown>, date: Date) =
.format(date) .format(date)
.split(" "); .split(" ");
return `${formattedDate[0]} ${locale.get("u_time_at")} ${formattedDate[1]}`; return `${formattedDate[0]} ${translation.get("u_time_at")} ${formattedDate[1]}`;
}; };
export enum TimeSecond { export enum TimeSecond {
Year = 31536000, Year = 60 * 60 * 24 * 365,
Week = 604800, Week = 60 * 60 * 24 * 7,
Day = 86400, Day = 60 * 60 * 24,
Hour = 3600, Hour = 60 * 60,
Minute = 60, Minute = 60,
Second = 1, Second = 1,
} }
@ -95,13 +95,31 @@ export const strToSeconds = (time: string) => {
/** /**
* Calculating the difference between a date and now * Calculating the difference between a date and now
* @param lang Locale
* @param time Time * @param time Time
* @returns Delta between the time and now * @returns Delta between the time and now
*/ */
export const timeDeltaToString = (time: number) => { export const timeDeltaToString = (time: number) => {
const now = Date.now(); const now = Date.now();
// TODO: adapt the output and not always parse the time as seconds let secondsDifference = Math.abs(Math.ceil((time - now) / 1000) - 2);
// https://git.mylloon.fr/ConfrerieDuKassoulait/Botanique/issues/189
// Use Intl.RelativeTimeFormat ? if (secondsDifference === 0) {
return `${strToSeconds(`${(now - time) / 1000}`)} secs`; return "0s";
}
return Object.entries(TimeSecond)
.map(([key, value]) => ({
label: key.charAt(0).toLowerCase(),
value: value as TimeSecond,
}))
.map(({ label, value }) => {
if (secondsDifference >= value) {
const amount = Math.floor(secondsDifference / value);
secondsDifference -= amount * value;
return `${amount}${label}`;
}
return null;
})
.filter(Boolean)
.join(" ");
}; };