UNPKG

@travetto/runtime

Version:

Runtime for travetto applications.

111 lines (101 loc) 3.46 kB
const MIN = 1000 * 60; const DAY = 24 * MIN * 60; const TIME_UNITS = { y: DAY * 365, M: DAY * 30, w: DAY * 7, d: DAY, h: MIN * 60, m: MIN, s: 1000, ms: 1 }; export type TimeSpan = `${number}${keyof typeof TIME_UNITS}`; export type TimeUnit = keyof typeof TIME_UNITS; const TIME_PATTERN = new RegExp(`^(?<amount>-?[0-9.]+)(?<unit>${Object.keys(TIME_UNITS).join('|')})$`); const TIME_LIKE_STRING = /\d{1,30}[a-z]$/i; export class TimeUtil { /** * Test to see if a string is valid for relative time * @param val */ static isTimeSpan(value: string): value is TimeSpan { return TIME_PATTERN.test(value); } /** * Returns time units convert to ms * @param amount Number of units to extend * @param unit Time unit to extend ('ms', 's', 'm', 'h', 'd', 'w', 'y') */ static asMillis(amount: Date | number | TimeSpan, unit?: TimeUnit): number { if (amount instanceof Date) { return amount.getTime(); } else if (typeof amount === 'string') { const groups: { amount?: string, unit?: TimeUnit } = amount.match(TIME_PATTERN)?.groups ?? {}; const amountString = groups.amount ?? `${amount}`; unit = groups.unit ?? unit ?? 'ms'; if (!TIME_UNITS[unit]) { return NaN; } amount = amountString.includes('.') ? parseFloat(amountString) : parseInt(amountString, 10); } return amount * TIME_UNITS[unit ?? 'ms']; } /** * Returns the time converted to seconds * @param date The date to convert */ static asSeconds(date: Date | number | TimeSpan, unit?: TimeUnit): number { return Math.trunc(this.asMillis(date, unit) / 1000); } /** * Returns the time converted to a Date * @param date The date to convert */ static asDate(date: Date | number | TimeSpan, unit?: TimeUnit): Date { return new Date(this.asMillis(date, unit)); } /** * Resolve time or span to possible time */ static fromValue(value: Date | number | string | undefined): number | undefined { switch (typeof value) { case 'number': return Number.isNaN(value) ? undefined : value; case 'object': return value.getTime(); case 'undefined': return undefined; case 'string': { if (TIME_LIKE_STRING.test(value)) { // Looks like span return this.isTimeSpan(value) ? this.asMillis(value) : undefined; } else { const parsed = parseInt(value, 10); return Number.isNaN(parsed) ? undefined : parsed; } } } } /** * Returns a new date with `amount` units into the future * @param amount Number of units to extend * @param unit Time unit to extend ('ms', 's', 'm', 'h', 'd', 'w', 'y') */ static fromNow(amount: number | TimeSpan, unit: TimeUnit = 'ms'): Date { return new Date(Date.now() + this.asMillis(amount, unit)); } /** * Returns a pretty timestamp * @param time Time in milliseconds */ static asClock(time: number): string { const rawSeconds = Math.trunc(time / 1000); const seconds = rawSeconds % 60; const minutes = Math.trunc(rawSeconds / 60) % 60; const hours = Math.trunc(rawSeconds / 3600); if (hours) { return `${hours.toString().padStart(2, '0')}h ${minutes.toString().padStart(2, '0')}m`; } else if (minutes) { return `${minutes.toString().padStart(2, '0')}m ${seconds.toString().padStart(2, '0')}s`; } else { return `${seconds.toString().padStart(2, '0')}s`; } } }