aboutsummaryrefslogtreecommitdiff
path: root/src/utils/text.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/text.ts')
-rw-r--r--src/utils/text.ts67
1 files changed, 50 insertions, 17 deletions
diff --git a/src/utils/text.ts b/src/utils/text.ts
index fae3343..115b3e2 100644
--- a/src/utils/text.ts
+++ b/src/utils/text.ts
@@ -37,25 +37,58 @@ export const wordsToPascal = (words: string[]) =>
export const wordsToTitle = (words: string[]) =>
words.map(w => w[0].toUpperCase() + w.slice(1)).join(" ");
+const units = ["years", "months", "weeks", "days", "hours", "minutes", "seconds"] as const;
+type Units = typeof units[number];
+
+function getUnitStr(unit: Units, isOne: boolean, short: boolean) {
+ if (short === false) return isOne ? unit.slice(0, -1) : unit;
+
+ return unit[0];
+}
+
/**
- * Forms milliseconds into a human readable string link "1 day, 2 hours, 3 minutes and 4 seconds"
- * @param ms Milliseconds
+ * Forms time into a human readable string link "1 day, 2 hours, 3 minutes and 4 seconds"
+ * @param time The time on the specified unit
+ * @param unit The unit the time is on
* @param short Whether to use short units like "d" instead of "days"
*/
-export function formatDuration(ms: number, short: boolean = false) {
- const dur = moment.duration(ms);
- return (["years", "months", "weeks", "days", "hours", "minutes", "seconds"] as const).reduce((res, unit) => {
- const x = dur[unit]();
- if (x > 0 || res.length) {
- if (res.length)
- res += unit === "seconds" ? " and " : ", ";
-
- const unitStr = short
- ? unit[0]
- : x === 1 ? unit.slice(0, -1) : unit;
-
- res += `${x} ${unitStr}`;
+export function formatDuration(time: number, unit: Units, short: boolean = false) {
+ const dur = moment.duration(time, unit);
+
+ let unitsAmounts = units.map(unit => ({ amount: dur[unit](), unit }));
+
+ let amountsToBeRemoved = 0;
+
+ outer:
+ for (let i = 0; i < unitsAmounts.length; i++) {
+ if (unitsAmounts[i].amount === 0 || !(i + 1 < unitsAmounts.length)) continue;
+ for (let v = i + 1; v < unitsAmounts.length; v++) {
+ if (unitsAmounts[v].amount !== 0) continue outer;
}
- return res;
- }, "").replace(/((,|and) \b0 \w+)+$/, "") || "now";
+
+ amountsToBeRemoved = unitsAmounts.length - (i + 1);
+ }
+ unitsAmounts = amountsToBeRemoved === 0 ? unitsAmounts : unitsAmounts.slice(0, -amountsToBeRemoved);
+
+ const daysAmountIndex = unitsAmounts.findIndex(({ unit }) => unit === "days");
+ if (daysAmountIndex !== -1) {
+ const daysAmount = unitsAmounts[daysAmountIndex];
+
+ const daysMod = daysAmount.amount % 7;
+ if (daysMod === 0) unitsAmounts.splice(daysAmountIndex, 1);
+ else daysAmount.amount = daysMod;
+ }
+
+ let res: string = "";
+ while (unitsAmounts.length) {
+ const { amount, unit } = unitsAmounts.shift()!;
+
+ if (res.length) res += unitsAmounts.length ? ", " : " and ";
+
+ if (amount > 0 || res.length) {
+ res += `${amount} ${getUnitStr(unit, amount === 1, short)}`;
+ }
+ }
+
+ return res.length ? res : `0 ${getUnitStr(unit, false, short)}`;
}