mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-26 18:56:39 +00:00
Improve duration formatting (#23025)
This commit is contained in:
parent
bc195c61cc
commit
164944ceff
@ -1,109 +0,0 @@
|
|||||||
import { DurationFormat } from "@formatjs/intl-durationformat";
|
|
||||||
import type { DurationInput } from "@formatjs/intl-durationformat/src/types";
|
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import type { FrontendLocaleData } from "../../data/translation";
|
|
||||||
import { round } from "../number/round";
|
|
||||||
|
|
||||||
export const DURATION_UNITS = ["ms", "s", "min", "h", "d"] as const;
|
|
||||||
|
|
||||||
type DurationUnit = (typeof DURATION_UNITS)[number];
|
|
||||||
|
|
||||||
const formatDurationDayMem = memoizeOne(
|
|
||||||
(locale: FrontendLocaleData) =>
|
|
||||||
new DurationFormat(locale.language, {
|
|
||||||
style: "narrow",
|
|
||||||
daysDisplay: "always",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const formatDurationHourMem = memoizeOne(
|
|
||||||
(locale: FrontendLocaleData) =>
|
|
||||||
new DurationFormat(locale.language, {
|
|
||||||
style: "narrow",
|
|
||||||
hoursDisplay: "always",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const formatDurationMinuteMem = memoizeOne(
|
|
||||||
(locale: FrontendLocaleData) =>
|
|
||||||
new DurationFormat(locale.language, {
|
|
||||||
style: "narrow",
|
|
||||||
minutesDisplay: "always",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const formatDurationSecondMem = memoizeOne(
|
|
||||||
(locale: FrontendLocaleData) =>
|
|
||||||
new DurationFormat(locale.language, {
|
|
||||||
style: "narrow",
|
|
||||||
secondsDisplay: "always",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const formatDurationMillisecondMem = memoizeOne(
|
|
||||||
(locale: FrontendLocaleData) =>
|
|
||||||
new DurationFormat(locale.language, {
|
|
||||||
style: "narrow",
|
|
||||||
millisecondsDisplay: "always",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
export const formatDuration = (
|
|
||||||
duration: string,
|
|
||||||
unit: DurationUnit,
|
|
||||||
precision: number | undefined,
|
|
||||||
locale: FrontendLocaleData
|
|
||||||
): string => {
|
|
||||||
const value =
|
|
||||||
precision !== undefined
|
|
||||||
? round(parseFloat(duration), precision)
|
|
||||||
: parseFloat(duration);
|
|
||||||
|
|
||||||
switch (unit) {
|
|
||||||
case "d": {
|
|
||||||
const days = Math.floor(value);
|
|
||||||
const hours = Math.floor((value - days) * 24);
|
|
||||||
const input: DurationInput = {
|
|
||||||
days,
|
|
||||||
hours,
|
|
||||||
};
|
|
||||||
return formatDurationDayMem(locale).format(input);
|
|
||||||
}
|
|
||||||
case "h": {
|
|
||||||
const hours = Math.floor(value);
|
|
||||||
const minutes = Math.floor((value - hours) * 60);
|
|
||||||
const input: DurationInput = {
|
|
||||||
hours,
|
|
||||||
minutes,
|
|
||||||
};
|
|
||||||
return formatDurationHourMem(locale).format(input);
|
|
||||||
}
|
|
||||||
case "min": {
|
|
||||||
const minutes = Math.floor(value);
|
|
||||||
const seconds = Math.floor((value - minutes) * 60);
|
|
||||||
const input: DurationInput = {
|
|
||||||
minutes,
|
|
||||||
seconds,
|
|
||||||
};
|
|
||||||
return formatDurationMinuteMem(locale).format(input);
|
|
||||||
}
|
|
||||||
case "s": {
|
|
||||||
const seconds = Math.floor(value);
|
|
||||||
const milliseconds = Math.floor((value - seconds) * 1000);
|
|
||||||
const input: DurationInput = {
|
|
||||||
seconds,
|
|
||||||
milliseconds,
|
|
||||||
};
|
|
||||||
return formatDurationSecondMem(locale).format(input);
|
|
||||||
}
|
|
||||||
case "ms": {
|
|
||||||
const milliseconds = Math.floor(value);
|
|
||||||
const input: DurationInput = {
|
|
||||||
milliseconds,
|
|
||||||
};
|
|
||||||
return formatDurationMillisecondMem(locale).format(input);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new Error("Invalid duration unit");
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,6 +1,9 @@
|
|||||||
import { DurationFormat } from "@formatjs/intl-durationformat";
|
import { DurationFormat } from "@formatjs/intl-durationformat";
|
||||||
|
import type { DurationInput } from "@formatjs/intl-durationformat/src/types";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
import type { HaDurationData } from "../../components/ha-duration-input";
|
import type { HaDurationData } from "../../components/ha-duration-input";
|
||||||
import type { FrontendLocaleData } from "../../data/translation";
|
import type { FrontendLocaleData } from "../../data/translation";
|
||||||
|
import { round } from "../number/round";
|
||||||
|
|
||||||
const leftPad = (num: number) => (num < 10 ? `0${num}` : num);
|
const leftPad = (num: number) => (num < 10 ? `0${num}` : num);
|
||||||
|
|
||||||
@ -44,10 +47,131 @@ export const formatNumericDuration = (
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const formatDurationLongMem = memoizeOne(
|
||||||
|
(locale: FrontendLocaleData) =>
|
||||||
|
new DurationFormat(locale.language, {
|
||||||
|
style: "long",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
export const formatDurationLong = (
|
export const formatDurationLong = (
|
||||||
locale: FrontendLocaleData,
|
locale: FrontendLocaleData,
|
||||||
duration: HaDurationData
|
duration: HaDurationData
|
||||||
) =>
|
) => formatDurationLongMem(locale).format(duration);
|
||||||
new DurationFormat(locale.language, {
|
|
||||||
style: "long",
|
const formatDigitalDurationMem = memoizeOne(
|
||||||
}).format(duration);
|
(locale: FrontendLocaleData) =>
|
||||||
|
new DurationFormat(locale.language, {
|
||||||
|
style: "digital",
|
||||||
|
hoursDisplay: "auto",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
export const formatDurationDigital = (
|
||||||
|
locale: FrontendLocaleData,
|
||||||
|
duration: HaDurationData
|
||||||
|
) => formatDigitalDurationMem(locale).format(duration);
|
||||||
|
|
||||||
|
export const DURATION_UNITS = ["ms", "s", "min", "h", "d"] as const;
|
||||||
|
|
||||||
|
type DurationUnit = (typeof DURATION_UNITS)[number];
|
||||||
|
|
||||||
|
const formatDurationDayMem = memoizeOne(
|
||||||
|
(locale: FrontendLocaleData) =>
|
||||||
|
new DurationFormat(locale.language, {
|
||||||
|
style: "narrow",
|
||||||
|
daysDisplay: "always",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const formatDurationHourMem = memoizeOne(
|
||||||
|
(locale: FrontendLocaleData) =>
|
||||||
|
new DurationFormat(locale.language, {
|
||||||
|
style: "narrow",
|
||||||
|
hoursDisplay: "always",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const formatDurationMinuteMem = memoizeOne(
|
||||||
|
(locale: FrontendLocaleData) =>
|
||||||
|
new DurationFormat(locale.language, {
|
||||||
|
style: "narrow",
|
||||||
|
minutesDisplay: "always",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const formatDurationSecondMem = memoizeOne(
|
||||||
|
(locale: FrontendLocaleData) =>
|
||||||
|
new DurationFormat(locale.language, {
|
||||||
|
style: "narrow",
|
||||||
|
secondsDisplay: "always",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const formatDurationMillisecondMem = memoizeOne(
|
||||||
|
(locale: FrontendLocaleData) =>
|
||||||
|
new DurationFormat(locale.language, {
|
||||||
|
style: "narrow",
|
||||||
|
millisecondsDisplay: "always",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
export const formatDuration = (
|
||||||
|
locale: FrontendLocaleData,
|
||||||
|
duration: string,
|
||||||
|
unit: DurationUnit,
|
||||||
|
precision?: number | undefined
|
||||||
|
): string => {
|
||||||
|
const value =
|
||||||
|
precision !== undefined
|
||||||
|
? round(parseFloat(duration), precision)
|
||||||
|
: parseFloat(duration);
|
||||||
|
|
||||||
|
switch (unit) {
|
||||||
|
case "d": {
|
||||||
|
const days = Math.floor(value);
|
||||||
|
const hours = Math.floor((value - days) * 24);
|
||||||
|
const input: DurationInput = {
|
||||||
|
days,
|
||||||
|
hours,
|
||||||
|
};
|
||||||
|
return formatDurationDayMem(locale).format(input);
|
||||||
|
}
|
||||||
|
case "h": {
|
||||||
|
const hours = Math.floor(value);
|
||||||
|
const minutes = Math.floor((value - hours) * 60);
|
||||||
|
const input: DurationInput = {
|
||||||
|
hours,
|
||||||
|
minutes,
|
||||||
|
};
|
||||||
|
return formatDurationHourMem(locale).format(input);
|
||||||
|
}
|
||||||
|
case "min": {
|
||||||
|
const minutes = Math.floor(value);
|
||||||
|
const seconds = Math.floor((value - minutes) * 60);
|
||||||
|
const input: DurationInput = {
|
||||||
|
minutes,
|
||||||
|
seconds,
|
||||||
|
};
|
||||||
|
return formatDurationMinuteMem(locale).format(input);
|
||||||
|
}
|
||||||
|
case "s": {
|
||||||
|
const seconds = Math.floor(value);
|
||||||
|
const milliseconds = Math.floor((value - seconds) * 1000);
|
||||||
|
const input: DurationInput = {
|
||||||
|
seconds,
|
||||||
|
milliseconds,
|
||||||
|
};
|
||||||
|
return formatDurationSecondMem(locale).format(input);
|
||||||
|
}
|
||||||
|
case "ms": {
|
||||||
|
const milliseconds = Math.floor(value);
|
||||||
|
const input: DurationInput = {
|
||||||
|
milliseconds,
|
||||||
|
};
|
||||||
|
return formatDurationMillisecondMem(locale).format(input);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new Error("Invalid duration unit");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -4,7 +4,7 @@ import type { EntityRegistryDisplayEntry } from "../../data/entity_registry";
|
|||||||
import type { FrontendLocaleData } from "../../data/translation";
|
import type { FrontendLocaleData } from "../../data/translation";
|
||||||
import { TimeZone } from "../../data/translation";
|
import { TimeZone } from "../../data/translation";
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import { DURATION_UNITS, formatDuration } from "../datetime/duration";
|
import { DURATION_UNITS, formatDuration } from "../datetime/format_duration";
|
||||||
import { formatDate } from "../datetime/format_date";
|
import { formatDate } from "../datetime/format_date";
|
||||||
import { formatDateTime } from "../datetime/format_date_time";
|
import { formatDateTime } from "../datetime/format_date_time";
|
||||||
import { formatTime } from "../datetime/format_time";
|
import { formatTime } from "../datetime/format_time";
|
||||||
@ -72,10 +72,10 @@ export const computeStateDisplayFromEntityAttributes = (
|
|||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
return formatDuration(
|
return formatDuration(
|
||||||
|
locale,
|
||||||
state,
|
state,
|
||||||
attributes.unit_of_measurement,
|
attributes.unit_of_measurement,
|
||||||
entity?.display_precision,
|
entity?.display_precision
|
||||||
locale
|
|
||||||
);
|
);
|
||||||
} catch (_err) {
|
} catch (_err) {
|
||||||
// fallback to default
|
// fallback to default
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import type { HassConfig } from "home-assistant-js-websocket";
|
import type { HassConfig } from "home-assistant-js-websocket";
|
||||||
import { ensureArray } from "../common/array/ensure-array";
|
import { ensureArray } from "../common/array/ensure-array";
|
||||||
import {
|
import {
|
||||||
formatNumericDuration,
|
|
||||||
formatDurationLong,
|
formatDurationLong,
|
||||||
|
formatNumericDuration,
|
||||||
} from "../common/datetime/format_duration";
|
} from "../common/datetime/format_duration";
|
||||||
import {
|
import {
|
||||||
formatTime,
|
formatTime,
|
||||||
@ -12,6 +12,10 @@ import secondsToDuration from "../common/datetime/seconds_to_duration";
|
|||||||
import { computeAttributeNameDisplay } from "../common/entity/compute_attribute_display";
|
import { computeAttributeNameDisplay } from "../common/entity/compute_attribute_display";
|
||||||
import { computeStateName } from "../common/entity/compute_state_name";
|
import { computeStateName } from "../common/entity/compute_state_name";
|
||||||
import { isValidEntityId } from "../common/entity/valid_entity_id";
|
import { isValidEntityId } from "../common/entity/valid_entity_id";
|
||||||
|
import {
|
||||||
|
formatListWithAnds,
|
||||||
|
formatListWithOrs,
|
||||||
|
} from "../common/string/format-list";
|
||||||
import type { HomeAssistant } from "../types";
|
import type { HomeAssistant } from "../types";
|
||||||
import type { Condition, ForDict, Trigger } from "./automation";
|
import type { Condition, ForDict, Trigger } from "./automation";
|
||||||
import type { DeviceCondition, DeviceTrigger } from "./device_automation";
|
import type { DeviceCondition, DeviceTrigger } from "./device_automation";
|
||||||
@ -21,10 +25,6 @@ import {
|
|||||||
} from "./device_automation";
|
} from "./device_automation";
|
||||||
import type { EntityRegistryEntry } from "./entity_registry";
|
import type { EntityRegistryEntry } from "./entity_registry";
|
||||||
import type { FrontendLocaleData } from "./translation";
|
import type { FrontendLocaleData } from "./translation";
|
||||||
import {
|
|
||||||
formatListWithAnds,
|
|
||||||
formatListWithOrs,
|
|
||||||
} from "../common/string/format-list";
|
|
||||||
import { isTriggerList } from "./trigger";
|
import { isTriggerList } from "./trigger";
|
||||||
|
|
||||||
const triggerTranslationBaseKey =
|
const triggerTranslationBaseKey =
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { formatNumericDuration } from "../common/datetime/format_duration";
|
import { formatDurationDigital } from "../common/datetime/format_duration";
|
||||||
import type { FrontendLocaleData } from "./translation";
|
import type { FrontendLocaleData } from "./translation";
|
||||||
|
|
||||||
export const STATE_ATTRIBUTES = [
|
export const STATE_ATTRIBUTES = [
|
||||||
@ -99,7 +99,11 @@ export const DOMAIN_ATTRIBUTES_FORMATERS: Record<
|
|||||||
},
|
},
|
||||||
media_player: {
|
media_player: {
|
||||||
volume_level: (value) => Math.round(value * 100).toString(),
|
volume_level: (value) => Math.round(value * 100).toString(),
|
||||||
media_duration: (value, locale) =>
|
media_duration: (value, locale) => {
|
||||||
formatNumericDuration(locale, { seconds: value })!,
|
const hours = Math.floor(value / 3600);
|
||||||
|
const minutes = Math.floor((value % 3600) / 60);
|
||||||
|
const seconds = value % 60;
|
||||||
|
return formatDurationDigital(locale, { hours, minutes, seconds })!;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -171,7 +171,8 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
|||||||
</ha-attribute-value>
|
</ha-attribute-value>
|
||||||
`
|
`
|
||||||
: this.hass.localize("state.default.unknown")
|
: this.hass.localize("state.default.unknown")
|
||||||
: isNumericState(stateObj) || this._config.unit
|
: (isNumericState(stateObj) || this._config.unit) &&
|
||||||
|
stateObj.attributes.device_class !== "duration"
|
||||||
? formatNumber(
|
? formatNumber(
|
||||||
stateObj.state,
|
stateObj.state,
|
||||||
this.hass.locale,
|
this.hass.locale,
|
||||||
@ -185,7 +186,8 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
|||||||
? html`
|
? html`
|
||||||
<span class="measurement"
|
<span class="measurement"
|
||||||
>${this._config.unit ||
|
>${this._config.unit ||
|
||||||
(this._config.attribute
|
(this._config.attribute ||
|
||||||
|
stateObj.attributes.device_class === "duration"
|
||||||
? ""
|
? ""
|
||||||
: stateObj.attributes.unit_of_measurement)}</span
|
: stateObj.attributes.unit_of_measurement)}</span
|
||||||
>
|
>
|
||||||
|
@ -1,90 +0,0 @@
|
|||||||
import { assert, describe, it } from "vitest";
|
|
||||||
|
|
||||||
import { formatDuration } from "../../../src/common/datetime/duration";
|
|
||||||
import type { FrontendLocaleData } from "../../../src/data/translation";
|
|
||||||
import {
|
|
||||||
DateFormat,
|
|
||||||
FirstWeekday,
|
|
||||||
NumberFormat,
|
|
||||||
TimeFormat,
|
|
||||||
TimeZone,
|
|
||||||
} from "../../../src/data/translation";
|
|
||||||
|
|
||||||
const LOCALE: FrontendLocaleData = {
|
|
||||||
language: "en",
|
|
||||||
number_format: NumberFormat.language,
|
|
||||||
time_format: TimeFormat.am_pm,
|
|
||||||
date_format: DateFormat.language,
|
|
||||||
time_zone: TimeZone.local,
|
|
||||||
first_weekday: FirstWeekday.language,
|
|
||||||
};
|
|
||||||
|
|
||||||
describe("formatDuration", () => {
|
|
||||||
it("works", () => {
|
|
||||||
assert.strictEqual(formatDuration("0", "ms", undefined, LOCALE), "0ms");
|
|
||||||
assert.strictEqual(formatDuration("1", "ms", undefined, LOCALE), "1ms");
|
|
||||||
assert.strictEqual(formatDuration("10", "ms", undefined, LOCALE), "10ms");
|
|
||||||
assert.strictEqual(formatDuration("100", "ms", undefined, LOCALE), "100ms");
|
|
||||||
assert.strictEqual(
|
|
||||||
formatDuration("1000", "ms", undefined, LOCALE),
|
|
||||||
"1,000ms"
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
formatDuration("1001", "ms", undefined, LOCALE),
|
|
||||||
"1,001ms"
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
formatDuration("65000", "ms", undefined, LOCALE),
|
|
||||||
"65,000ms"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
formatDuration("0.5", "s", undefined, LOCALE),
|
|
||||||
"0s 500ms"
|
|
||||||
);
|
|
||||||
assert.strictEqual(formatDuration("1", "s", undefined, LOCALE), "1s");
|
|
||||||
assert.strictEqual(
|
|
||||||
formatDuration("1.1", "s", undefined, LOCALE),
|
|
||||||
"1s 100ms"
|
|
||||||
);
|
|
||||||
assert.strictEqual(formatDuration("65", "s", undefined, LOCALE), "65s");
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
formatDuration("0.25", "min", undefined, LOCALE),
|
|
||||||
"0m 15s"
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
formatDuration("0.5", "min", undefined, LOCALE),
|
|
||||||
"0m 30s"
|
|
||||||
);
|
|
||||||
assert.strictEqual(formatDuration("1", "min", undefined, LOCALE), "1m");
|
|
||||||
assert.strictEqual(formatDuration("20", "min", undefined, LOCALE), "20m");
|
|
||||||
assert.strictEqual(
|
|
||||||
formatDuration("95.5", "min", undefined, LOCALE),
|
|
||||||
"95m 30s"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
formatDuration("0.25", "h", undefined, LOCALE),
|
|
||||||
"0h 15m"
|
|
||||||
);
|
|
||||||
assert.strictEqual(formatDuration("0.5", "h", undefined, LOCALE), "0h 30m");
|
|
||||||
assert.strictEqual(formatDuration("1", "h", undefined, LOCALE), "1h");
|
|
||||||
assert.strictEqual(formatDuration("20", "h", undefined, LOCALE), "20h");
|
|
||||||
assert.strictEqual(
|
|
||||||
formatDuration("95.5", "h", undefined, LOCALE),
|
|
||||||
"95h 30m"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.strictEqual(formatDuration("0", "d", undefined, LOCALE), "0d");
|
|
||||||
assert.strictEqual(formatDuration("0.4", "d", undefined, LOCALE), "0d 9h");
|
|
||||||
assert.strictEqual(formatDuration("1", "d", undefined, LOCALE), "1d");
|
|
||||||
assert.strictEqual(formatDuration("20", "d", undefined, LOCALE), "20d");
|
|
||||||
assert.strictEqual(
|
|
||||||
formatDuration("95.5", "d", undefined, LOCALE),
|
|
||||||
"95d 12h"
|
|
||||||
);
|
|
||||||
assert.strictEqual(formatDuration("95.75", "d", 0, LOCALE), "96d");
|
|
||||||
assert.strictEqual(formatDuration("95.75", "d", 2, LOCALE), "95d 18h");
|
|
||||||
});
|
|
||||||
});
|
|
57
test/common/datetime/format_duration.test.ts
Normal file
57
test/common/datetime/format_duration.test.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { assert, describe, it } from "vitest";
|
||||||
|
|
||||||
|
import { formatDuration } from "../../../src/common/datetime/format_duration";
|
||||||
|
import type { FrontendLocaleData } from "../../../src/data/translation";
|
||||||
|
import {
|
||||||
|
DateFormat,
|
||||||
|
FirstWeekday,
|
||||||
|
NumberFormat,
|
||||||
|
TimeFormat,
|
||||||
|
TimeZone,
|
||||||
|
} from "../../../src/data/translation";
|
||||||
|
|
||||||
|
const LOCALE: FrontendLocaleData = {
|
||||||
|
language: "en",
|
||||||
|
number_format: NumberFormat.language,
|
||||||
|
time_format: TimeFormat.am_pm,
|
||||||
|
date_format: DateFormat.language,
|
||||||
|
time_zone: TimeZone.local,
|
||||||
|
first_weekday: FirstWeekday.language,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("formatDuration", () => {
|
||||||
|
it("works", () => {
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "0", "ms"), "0ms");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "1", "ms"), "1ms");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "10", "ms"), "10ms");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "100", "ms"), "100ms");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "1000", "ms"), "1,000ms");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "1001", "ms"), "1,001ms");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "65000", "ms"), "65,000ms");
|
||||||
|
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "0.5", "s"), "0s 500ms");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "1", "s"), "1s");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "1.1", "s"), "1s 100ms");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "65", "s"), "65s");
|
||||||
|
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "0.25", "min"), "0m 15s");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "0.5", "min"), "0m 30s");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "1", "min"), "1m");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "20", "min"), "20m");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "95.5", "min"), "95m 30s");
|
||||||
|
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "0.25", "h"), "0h 15m");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "0.5", "h"), "0h 30m");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "1", "h"), "1h");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "20", "h"), "20h");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "95.5", "h"), "95h 30m");
|
||||||
|
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "0", "d"), "0d");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "0.4", "d"), "0d 9h");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "1", "d"), "1d");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "20", "d"), "20d");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "95.5", "d"), "95d 12h");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "95.75", "d", 0), "96d");
|
||||||
|
assert.strictEqual(formatDuration(LOCALE, "95.75", "d", 2), "95d 18h");
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user