2024-01-01 21:11:32 +00:00
|
|
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
2023-03-18 12:36:00 +00:00
|
|
|
// This module is browser compatible.
|
2022-11-25 11:40:23 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Format milliseconds to time duration.
|
|
|
|
*
|
|
|
|
* ```ts
|
2024-04-29 02:57:30 +00:00
|
|
|
* import { format } from "@std/fmt/duration";
|
refactor(assert,async,bytes,cli,collections,crypto,csv,data-structures,datetime,dotenv,encoding,expect,fmt,front-matter,fs,html,http,ini,internal,io,json,jsonc,log,media-types,msgpack,net,path,semver,streams,testing,text,toml,ulid,url,uuid,webgpu,yaml): import from `@std/assert` (#5199)
* refactor: import from `@std/assert`
* update
2024-06-30 08:30:10 +00:00
|
|
|
* import { assertEquals } from "@std/assert";
|
2022-11-25 11:40:23 +00:00
|
|
|
*
|
2024-06-03 04:10:27 +00:00
|
|
|
* assertEquals(format(99674, { style: "digital" }), "00:00:01:39:674:000:000");
|
2022-11-25 11:40:23 +00:00
|
|
|
*
|
2024-06-03 04:10:27 +00:00
|
|
|
* assertEquals(format(99674), "0d 0h 1m 39s 674ms 0µs 0ns");
|
2022-11-25 11:40:23 +00:00
|
|
|
*
|
2024-06-03 04:10:27 +00:00
|
|
|
* assertEquals(format(99674, { ignoreZero: true }), "1m 39s 674ms");
|
2022-11-25 11:40:23 +00:00
|
|
|
*
|
2024-06-03 04:10:27 +00:00
|
|
|
* assertEquals(format(99674, { style: "full", ignoreZero: true }), "1 minutes, 39 seconds, 674 milliseconds");
|
2022-11-25 11:40:23 +00:00
|
|
|
* ```
|
|
|
|
* @module
|
|
|
|
*/
|
2022-11-10 15:05:42 +00:00
|
|
|
|
2023-10-11 07:19:48 +00:00
|
|
|
function addZero(num: number, digits: number) {
|
|
|
|
return String(num).padStart(digits, "0");
|
|
|
|
}
|
2022-11-10 15:05:42 +00:00
|
|
|
|
2022-11-18 03:59:19 +00:00
|
|
|
interface DurationObject {
|
2022-11-10 15:05:42 +00:00
|
|
|
d: number;
|
|
|
|
h: number;
|
|
|
|
m: number;
|
|
|
|
s: number;
|
|
|
|
ms: number;
|
|
|
|
us: number;
|
|
|
|
ns: number;
|
|
|
|
}
|
|
|
|
|
2022-11-18 03:59:19 +00:00
|
|
|
const keyList: Record<keyof DurationObject, string> = {
|
2022-11-10 15:05:42 +00:00
|
|
|
d: "days",
|
|
|
|
h: "hours",
|
|
|
|
m: "minutes",
|
|
|
|
s: "seconds",
|
|
|
|
ms: "milliseconds",
|
|
|
|
us: "microseconds",
|
|
|
|
ns: "nanoseconds",
|
|
|
|
};
|
|
|
|
|
2023-09-25 01:28:27 +00:00
|
|
|
/** Parse milliseconds into a duration. */
|
2022-11-18 03:59:19 +00:00
|
|
|
function millisecondsToDurationObject(ms: number): DurationObject {
|
2022-11-10 15:05:42 +00:00
|
|
|
// Duration cannot be negative
|
2023-11-08 08:28:04 +00:00
|
|
|
const millis = Math.abs(ms);
|
|
|
|
const millisFraction = millis.toFixed(7).slice(-7, -1);
|
2022-11-10 15:05:42 +00:00
|
|
|
return {
|
2023-11-08 08:28:04 +00:00
|
|
|
d: Math.trunc(millis / 86400000),
|
|
|
|
h: Math.trunc(millis / 3600000) % 24,
|
|
|
|
m: Math.trunc(millis / 60000) % 60,
|
|
|
|
s: Math.trunc(millis / 1000) % 60,
|
|
|
|
ms: Math.trunc(millis) % 1000,
|
|
|
|
us: +millisFraction.slice(0, 3),
|
|
|
|
ns: +millisFraction.slice(3, 6),
|
2022-11-10 15:05:42 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function durationArray(
|
2022-11-18 03:59:19 +00:00
|
|
|
duration: DurationObject,
|
|
|
|
): { type: keyof DurationObject; value: number }[] {
|
2022-11-10 15:05:42 +00:00
|
|
|
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 },
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2024-01-11 06:57:29 +00:00
|
|
|
/** Options for {@linkcode format}. */
|
2024-07-31 10:23:43 +00:00
|
|
|
export interface FormatOptions {
|
2022-11-10 15:05:42 +00:00
|
|
|
/**
|
2024-07-31 10:23:43 +00:00
|
|
|
* The style for formatting the duration.
|
|
|
|
*
|
2022-11-18 03:59:19 +00:00
|
|
|
* "narrow" for "0d 0h 0m 0s 0ms..."
|
|
|
|
* "digital" for "00:00:00:00:000..."
|
2022-11-10 15:05:42 +00:00
|
|
|
* "full" for "0 days, 0 hours, 0 minutes,..."
|
2024-07-31 10:23:43 +00:00
|
|
|
*
|
|
|
|
* @default {"narrow"}
|
2022-11-10 15:05:42 +00:00
|
|
|
*/
|
2024-07-31 10:23:43 +00:00
|
|
|
style?: "narrow" | "digital" | "full";
|
2022-11-10 15:05:42 +00:00
|
|
|
/**
|
|
|
|
* Whether to ignore zero values.
|
2022-11-18 03:59:19 +00:00
|
|
|
* With style="narrow" | "full", all zero values are ignored.
|
|
|
|
* With style="digital", only values in the ends are ignored.
|
2024-07-31 10:23:43 +00:00
|
|
|
*
|
|
|
|
* @default {false}
|
2022-11-10 15:05:42 +00:00
|
|
|
*/
|
2024-07-31 10:23:43 +00:00
|
|
|
ignoreZero?: boolean;
|
2022-11-10 15:05:42 +00:00
|
|
|
}
|
|
|
|
|
2024-01-11 06:57:29 +00:00
|
|
|
/**
|
|
|
|
* Format milliseconds to time duration.
|
|
|
|
*
|
2024-05-28 06:14:34 +00:00
|
|
|
* @example Usage
|
2024-01-11 06:57:29 +00:00
|
|
|
* ```ts
|
2024-04-29 02:57:30 +00:00
|
|
|
* import { format } from "@std/fmt/duration";
|
refactor(assert,async,bytes,cli,collections,crypto,csv,data-structures,datetime,dotenv,encoding,expect,fmt,front-matter,fs,html,http,ini,internal,io,json,jsonc,log,media-types,msgpack,net,path,semver,streams,testing,text,toml,ulid,url,uuid,webgpu,yaml): import from `@std/assert` (#5199)
* refactor: import from `@std/assert`
* update
2024-06-30 08:30:10 +00:00
|
|
|
* import { assertEquals } from "@std/assert";
|
2024-01-11 06:57:29 +00:00
|
|
|
*
|
2024-06-03 04:10:27 +00:00
|
|
|
* assertEquals(format(99674, { style: "digital" }), "00:00:01:39:674:000:000");
|
|
|
|
*
|
|
|
|
* assertEquals(format(99674), "0d 0h 1m 39s 674ms 0µs 0ns");
|
|
|
|
*
|
|
|
|
* assertEquals(format(99674, { ignoreZero: true }), "1m 39s 674ms");
|
|
|
|
*
|
|
|
|
* assertEquals(format(99674, { style: "full", ignoreZero: true }), "1 minutes, 39 seconds, 674 milliseconds");
|
2024-01-11 06:57:29 +00:00
|
|
|
* ```
|
2024-05-28 06:14:34 +00:00
|
|
|
*
|
|
|
|
* @param ms The milliseconds value to format
|
|
|
|
* @param options The options for formatting
|
|
|
|
* @returns The formatted string
|
2024-01-11 06:57:29 +00:00
|
|
|
*/
|
2022-11-18 03:59:19 +00:00
|
|
|
export function format(
|
2022-11-10 15:05:42 +00:00
|
|
|
ms: number,
|
2024-09-03 08:57:27 +00:00
|
|
|
options?: FormatOptions,
|
2022-11-10 15:05:42 +00:00
|
|
|
): string {
|
2024-09-03 08:57:27 +00:00
|
|
|
const {
|
|
|
|
style = "narrow",
|
|
|
|
ignoreZero = false,
|
|
|
|
} = options ?? {};
|
|
|
|
|
2022-11-18 03:59:19 +00:00
|
|
|
const duration = millisecondsToDurationObject(ms);
|
2022-11-10 15:05:42 +00:00
|
|
|
const durationArr = durationArray(duration);
|
2024-09-03 08:57:27 +00:00
|
|
|
switch (style) {
|
2022-11-18 03:59:19 +00:00
|
|
|
case "narrow": {
|
2024-09-03 08:57:27 +00:00
|
|
|
if (ignoreZero) {
|
2022-11-10 15:05:42 +00:00
|
|
|
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": {
|
2024-09-03 08:57:27 +00:00
|
|
|
if (ignoreZero) {
|
2022-11-10 15:05:42 +00:00
|
|
|
return `${
|
|
|
|
durationArr.filter((x) => x.value).map((x) =>
|
|
|
|
`${x.value} ${keyList[x.type]}`
|
|
|
|
).join(", ")
|
|
|
|
}`;
|
|
|
|
}
|
|
|
|
return `${
|
|
|
|
durationArr.map((x) => `${x.value} ${keyList[x.type]}`).join(", ")
|
|
|
|
}`;
|
|
|
|
}
|
2022-11-18 03:59:19 +00:00
|
|
|
case "digital": {
|
2022-11-10 15:05:42 +00:00
|
|
|
const arr = durationArr.map((x) =>
|
|
|
|
["ms", "us", "ns"].includes(x.type)
|
|
|
|
? addZero(x.value, 3)
|
|
|
|
: addZero(x.value, 2)
|
|
|
|
);
|
2024-09-03 08:57:27 +00:00
|
|
|
if (ignoreZero) {
|
2022-11-10 15:05:42 +00:00
|
|
|
let cont = true;
|
|
|
|
while (cont) {
|
|
|
|
if (!Number(arr[arr.length - 1])) arr.pop();
|
|
|
|
else cont = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return arr.join(":");
|
|
|
|
}
|
|
|
|
default: {
|
2022-11-18 03:59:19 +00:00
|
|
|
throw new TypeError(`style must be "narrow", "full", or "digital"!`);
|
2022-11-10 15:05:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|