/
duration.ts
127 lines (120 loc) · 3.26 KB
/
duration.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// A module to get formatted time duration from milliseconds.
const addZero = (num: number, digits: number) =>
String(num).padStart(digits, "0");
interface DurationObj {
d: number;
h: number;
m: number;
s: number;
ms: number;
us: number;
ns: number;
}
const keyList: Record<keyof DurationObj, string> = {
d: "days",
h: "hours",
m: "minutes",
s: "seconds",
ms: "milliseconds",
us: "microseconds",
ns: "nanoseconds",
};
/** Parse milleseconds into a duration. */
function parseDuration(ms: number): DurationObj {
// Duration cannot be negative
const absolute_ms = Math.abs(ms);
return {
d: Math.trunc(absolute_ms / 86400000),
h: Math.trunc(absolute_ms / 3600000) % 24,
m: Math.trunc(absolute_ms / 60000) % 60,
s: Math.trunc(absolute_ms / 1000) % 60,
ms: Math.trunc(absolute_ms) % 1000,
us: Math.trunc(absolute_ms * 1000) % 1000,
ns: Math.trunc(absolute_ms * 1000000) % 1000,
};
}
function durationArray(
duration: DurationObj,
): { type: keyof DurationObj; value: number }[] {
return [
{ type: "d", value: duration.d },
{ type: "h", value: duration.h },
{ type: "m", value: duration.m },
{ type: "s", value: duration.s },
{ type: "ms", value: duration.ms },
{ type: "us", value: duration.us },
{ type: "ns", value: duration.ns },
];
}
export interface PrettyDurationOptions {
/**
* "short" for "0d 0h 0m 0s 0ms..."
* "time" for "00:00:00:00:000..."
* "full" for "0 days, 0 hours, 0 minutes,..."
*/
formatType: "short" | "time" | "full";
/**
* Whether to ignore zero values.
* With formatType="short" | "full", all zero values are ignored.
* With formatType="time", only values in the ends are ignored.
*/
ignoreZero: boolean;
}
export function prettyDuration(
ms: number,
options: Partial<PrettyDurationOptions> = {},
): string {
const opt = Object.assign(
{ formatType: "short", ignoreZero: false },
options,
);
const duration = parseDuration(ms);
const durationArr = durationArray(duration);
switch (opt.formatType) {
case "short": {
if (opt.ignoreZero) {
return `${
durationArr.filter((x) => x.value).map((x) =>
`${x.value}${x.type === "us" ? "µs" : x.type}`
)
.join(" ")
}`;
}
return `${
durationArr.map((x) => `${x.value}${x.type === "us" ? "µs" : x.type}`)
.join(" ")
}`;
}
case "full": {
if (opt.ignoreZero) {
return `${
durationArr.filter((x) => x.value).map((x) =>
`${x.value} ${keyList[x.type]}`
).join(", ")
}`;
}
return `${
durationArr.map((x) => `${x.value} ${keyList[x.type]}`).join(", ")
}`;
}
case "time": {
const arr = durationArr.map((x) =>
["ms", "us", "ns"].includes(x.type)
? addZero(x.value, 3)
: addZero(x.value, 2)
);
if (opt.ignoreZero) {
let cont = true;
while (cont) {
if (!Number(arr[arr.length - 1])) arr.pop();
else cont = false;
}
}
return arr.join(":");
}
default: {
throw new TypeError(`formatType must be "short", "full", or "time"!`);
}
}
}