import type { MaybeNumber } from 'ontime-types'; import { millisToSeconds, secondsToHours, secondsToMinutes } from './conversionUtils.js'; function pad(val: number): string { return String(val).padStart(2, '0'); } type FormatOptions = { fallback?: string; }; /** * Converts a value in milliseconds to its time tag * @param millis time to convert * @param options optional overloads for format * @returns formatted time such as 12:00:00 */ export function millisToString(millis?: MaybeNumber, options?: FormatOptions): string { if (millis == null) { return options?.fallback ?? '...'; } const isNegative = millis < 0; const totalSeconds = Math.abs(millisToSeconds(millis)); const seconds = totalSeconds % 60; const minutes = secondsToMinutes(totalSeconds) % 60; const hours = secondsToHours(totalSeconds); return `${isNegative ? '-' : ''}${[hours, minutes, seconds].map(pad).join(':')}`; } /** * Receives a string such as 00:10:10 and removes the hours field if it is 00 * @param timer */ export function removeLeadingZero(timer: string): string { if (timer.startsWith('00:0')) { return timer.slice(4); } if (timer.startsWith('00:')) { return timer.slice(3); } if (timer.startsWith('-00:0')) { return `-${timer.slice(5)}`; } if (timer.startsWith('-00:')) { return `-${timer.slice(4)}`; } return timer; } /** * Receives a string such as 00:10:10 and removes the seconds field if it is 00 * @param timer */ export function removeTrailingZero(timer: string): string { if (timer.endsWith(':00')) { return timer.slice(0, -3); } return timer; } /** * Receives a string such as 00:10:10 and removes the seconds field * @param timer */ export function removeSeconds(timer: string): string { return timer.slice(0, -3); } /** * Formats a given date into a custom string format based on UTC time. * * @param millis - The number of milliseconds. * @param format - A string specifying the desired output format. * For example, 'ss' will format the millis as '07' seconds. * * @returns The formatted date as a string according to the provided `format` string. * If input `millis` is smaller than zero, it returns undefined. * */ export function formatFromMillis(millis: number, format: string): string | undefined { if (millis < 0) { return undefined; } const date: Date = new Date(millis); const hour24Padded = date.getUTCHours().toString().padStart(2, '0'); const hour24 = date.getUTCHours().toString(); const minutePadded = date.getUTCMinutes().toString().padStart(2, '0'); const minute = date.getUTCMinutes().toString(); const secondPadded = date.getUTCSeconds().toString().padStart(2, '0'); const second = date.getUTCSeconds().toString(); const milliseconds = date.getUTCMilliseconds().toString().padStart(3, '0'); const hour12 = (date.getUTCHours() % 12 || 12).toString(); const hour12Padded = hour12.padStart(2, '0'); const amPm = date.getUTCHours() >= 12 ? 'PM' : 'AM'; const replacements: Record = { HH: hour24Padded, H: hour24, hh: hour12Padded, h: hour12, mm: minutePadded, m: minute, ss: secondPadded, s: second, S: milliseconds, a: amPm, }; return applyReplacements(format, replacements); } /** * Applies replacements to a template string based on a dictionary of tokens and their corresponding values. * * @param {string} template - The format template string containing tokens to be replaced. * @param {Record} replacements - A record of tokens and their corresponding values. * @returns {string} The formatted string with all tokens replaced by their values. */ function applyReplacements(template: string, replacements: Record): string { return Object.keys(replacements).reduce((result, token) => { const regex = new RegExp(`\\b${token}\\b`, 'g'); return result.replace(regex, replacements[token]); }, template); }