123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- import {Timespan, Unit} from 'sentry/utils/duration/types';
- import {formatSecondsToClock} from 'sentry/utils/formatters';
- type Format =
- // example: `3,600`
- | 'count-locale'
- // example: `86400`
- | 'count'
- // example: `1:00:00.000`
- | 'h:mm:ss.sss'
- // example: `1:00:00`
- | 'h:mm:ss'
- // example: `01:00:00.000
- | 'hh:mm:ss.sss'
- // example: `01:00:00`
- | 'hh:mm:ss';
- type Args = {
- /**
- * The precision of the output.
- *
- * If the output precision is more granular than the input precision you might
- * find the output value is rounded down, because least-significant digits are
- * simply chopped off.
- * Alternativly, because of IEEE 754, converting from a granular precision to
- * something less granular might, in some cases, change the least-significant
- * digits of the final value.
- */
- precision: Unit;
- /**
- * The output style to use
- *
- * ie: 120 seconds formatted as "h:mm" results in "2:00"
- * ie: 10500 formatted as "count" + "sec" results in "10.5"
- */
- style: Format;
- /**
- * The timespan/duration to be displayed
- * ie: "1000 miliseconds" would have the same output as "1 second"
- *
- * If it's coming from javascript `new Date` then 'ms'
- * If it's from an SDK event, probably 'sec'
- */
- timespan: Timespan;
- };
- const PRECISION_FACTORS: Record<Unit, number> = {
- ms: 1,
- sec: 1000,
- min: 1000 * 60,
- hour: 1000 * 60 * 60,
- day: 1000 * 60 * 60 * 24,
- week: 1000 * 60 * 60 * 24 * 7,
- };
- /**
- * Format a timespan (aka duration) into a formatted string.
- *
- * A timespan is expressed a `number` and a `unit` pair -> [value, unit]
- */
- export default function formatDuration({
- precision,
- style,
- timespan: [value, unit],
- }: Args): string {
- const ms = normalizeTimespanToMs(value, unit);
- const valueInUnit = msToPrecision(ms, precision);
- switch (style) {
- case 'count-locale':
- return valueInUnit.toLocaleString();
- case 'count':
- return String(valueInUnit);
- case 'h:mm:ss': // fall-through
- case 'hh:mm:ss': // fall-through
- case 'h:mm:ss.sss': // fall-through
- case 'hh:mm:ss.sss':
- const includeMs = style.endsWith('.sss');
- const valueInSec = msToPrecision(ms, 'sec');
- const str = formatSecondsToClock(valueInSec, {
- padAll: style.startsWith('hh:mm:ss'),
- });
- const [head, tail] = str.split('.');
- return includeMs ? [head, tail ?? '000'].join('.') : String(head);
- default:
- throw new Error('Invalid style');
- }
- }
- function normalizeTimespanToMs(value: number, unit: Unit): number {
- const factor = PRECISION_FACTORS[unit];
- return value * factor;
- }
- function msToPrecision(value: number, unit: Unit): number {
- if (value === 0) {
- return 0;
- }
- const factor = PRECISION_FACTORS[unit];
- return value / factor;
- }
|