-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use explicit duration format for state formatting (#23017)
- Loading branch information
Showing
12 changed files
with
222 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,109 @@ | ||
import millisecondsToDuration from "./milliseconds_to_duration"; | ||
|
||
const DAY_IN_MILLISECONDS = 86400000; | ||
const HOUR_IN_MILLISECONDS = 3600000; | ||
const MINUTE_IN_MILLISECONDS = 60000; | ||
const SECOND_IN_MILLISECONDS = 1000; | ||
|
||
export const UNIT_TO_MILLISECOND_CONVERT = { | ||
ms: 1, | ||
s: SECOND_IN_MILLISECONDS, | ||
min: MINUTE_IN_MILLISECONDS, | ||
h: HOUR_IN_MILLISECONDS, | ||
d: DAY_IN_MILLISECONDS, | ||
}; | ||
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", | ||
}) | ||
); | ||
|
||
export const formatDuration = (duration: string, units: string): string => | ||
millisecondsToDuration( | ||
parseFloat(duration) * UNIT_TO_MILLISECOND_CONVERT[units] | ||
) || "0"; | ||
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"); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,90 @@ | ||
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"), "0"); | ||
assert.strictEqual(formatDuration("1", "ms"), "0.001"); | ||
assert.strictEqual(formatDuration("10", "ms"), "0.010"); | ||
assert.strictEqual(formatDuration("100", "ms"), "0.100"); | ||
assert.strictEqual(formatDuration("1000", "ms"), "1"); | ||
assert.strictEqual(formatDuration("1001", "ms"), "1.001"); | ||
assert.strictEqual(formatDuration("65000", "ms"), "1:05"); | ||
assert.strictEqual(formatDuration("3665000", "ms"), "1:01:05"); | ||
assert.strictEqual(formatDuration("39665050", "ms"), "11:01:05"); | ||
assert.strictEqual(formatDuration("932093000", "ms"), "258:54:53"); | ||
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", "s"), "0"); | ||
assert.strictEqual(formatDuration("1", "s"), "1"); | ||
assert.strictEqual(formatDuration("1.1", "s"), "1.100"); | ||
assert.strictEqual(formatDuration("65", "s"), "1:05"); | ||
assert.strictEqual(formatDuration("3665", "s"), "1:01:05"); | ||
assert.strictEqual(formatDuration("39665", "s"), "11:01:05"); | ||
assert.strictEqual(formatDuration("932093", "s"), "258:54:53"); | ||
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", "min"), "0"); | ||
assert.strictEqual(formatDuration("65", "min"), "1:05:00"); | ||
assert.strictEqual(formatDuration("3665", "min"), "61:05:00"); | ||
assert.strictEqual(formatDuration("39665", "min"), "661:05:00"); | ||
assert.strictEqual(formatDuration("932093", "min"), "15534:53:00"); | ||
assert.strictEqual(formatDuration("12.4", "min"), "12:24"); | ||
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", "h"), "0"); | ||
assert.strictEqual(formatDuration("65", "h"), "65:00:00"); | ||
assert.strictEqual(formatDuration("3665", "h"), "3665:00:00"); | ||
assert.strictEqual(formatDuration("39665", "h"), "39665:00:00"); | ||
assert.strictEqual(formatDuration("932093", "h"), "932093:00:00"); | ||
assert.strictEqual(formatDuration("24.3", "h"), "24:18:00"); | ||
assert.strictEqual(formatDuration("24.32423", "h"), "24:19:27"); | ||
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"), "0"); | ||
assert.strictEqual(formatDuration("65", "d"), "1560:00:00"); | ||
assert.strictEqual(formatDuration("3665", "d"), "87960:00:00"); | ||
assert.strictEqual(formatDuration("39665", "d"), "951960:00:00"); | ||
assert.strictEqual(formatDuration("932093", "d"), "22370232:00:00"); | ||
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"); | ||
}); | ||
}); |
Oops, something went wrong.