diff --git a/web/src/lib/media/duration.test.ts b/web/src/lib/media/duration.test.ts new file mode 100644 index 00000000..91427e32 --- /dev/null +++ b/web/src/lib/media/duration.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, test } from 'vitest'; +import { formatDuration } from './duration'; + +describe('formatDuration', () => { + test('under a minute renders 0:SS', () => { + expect(formatDuration(42)).toBe('0:42'); + expect(formatDuration(5)).toBe('0:05'); + }); + + test('under an hour renders M:SS', () => { + expect(formatDuration(242)).toBe('4:02'); + expect(formatDuration(600)).toBe('10:00'); + }); + + test('at or above an hour renders H:MM:SS', () => { + expect(formatDuration(3600)).toBe('1:00:00'); + expect(formatDuration(3723)).toBe('1:02:03'); + expect(formatDuration(36000)).toBe('10:00:00'); + }); + + test('zero renders 0:00', () => { + expect(formatDuration(0)).toBe('0:00'); + }); + + test('negative values clamp to 0:00', () => { + expect(formatDuration(-1)).toBe('0:00'); + expect(formatDuration(-100)).toBe('0:00'); + }); + + test('fractional seconds floor', () => { + expect(formatDuration(61.9)).toBe('1:01'); + }); +}); diff --git a/web/src/lib/media/duration.ts b/web/src/lib/media/duration.ts new file mode 100644 index 00000000..90102f69 --- /dev/null +++ b/web/src/lib/media/duration.ts @@ -0,0 +1,15 @@ +// Formats a non-negative number of seconds as `mm:ss` when under an hour, +// `h:mm:ss` otherwise. Negative values clamp to zero (callers shouldn't +// pass them, but the UI shouldn't crash if they do). +export function formatDuration(seconds: number): string { + const total = Math.max(0, Math.floor(seconds)); + const h = Math.floor(total / 3600); + const m = Math.floor((total % 3600) / 60); + const s = total % 60; + const ss = String(s).padStart(2, '0'); + if (h > 0) { + const mm = String(m).padStart(2, '0'); + return `${h}:${mm}:${ss}`; + } + return `${m}:${ss}`; +}