diff options
Diffstat (limited to 'src/utils/text.ts')
-rw-r--r-- | src/utils/text.ts | 67 |
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)}`; } |