Skip to content

Commit

Permalink
fix duration formatting
Browse files Browse the repository at this point in the history
fixes #1603
  • Loading branch information
mifi committed Jul 25, 2023
1 parent 33450e4 commit c5fb004
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 21 deletions.
2 changes: 1 addition & 1 deletion src/edlFormats.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export function parseYouTube(str) {

export function formatYouTube(segments) {
return segments.map((segment) => {
const timeStr = formatDuration({ seconds: segment.start, showMs: false, shorten: true });
const timeStr = formatDuration({ seconds: segment.start, showFraction: false, shorten: true });
const namePart = segment.name ? ` ${segment.name}` : '';
return `${timeStr}${namePart}`;
}).join('\n');
Expand Down
41 changes: 23 additions & 18 deletions src/util/duration.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import padStart from 'lodash/padStart';

export function formatDuration({ seconds: secondsIn, fileNameFriendly, showMs = true, shorten = false, fps }) {
const seconds = secondsIn || 0;
const secondsAbs = Math.abs(seconds);
const minutes = Math.floor((secondsAbs / 60) % 60);
const hours = Math.floor(secondsAbs / 60 / 60);
export function formatDuration({ seconds: totalSecondsIn, fileNameFriendly, showFraction = true, shorten = false, fps }) {
const totalSeconds = totalSecondsIn || 0;
const totalSecondsAbs = Math.abs(totalSeconds);
const sign = totalSeconds < 0 ? '-' : '';

const unitsPerSec = fps != null ? fps : 1000;

// round to integer for our current unit
const totalUnits = Math.round(totalSecondsAbs * unitsPerSec);

const seconds = Math.floor(totalUnits / unitsPerSec);
const secondsPadded = padStart(seconds % 60, 2, '0');
const minutes = Math.floor((totalUnits / 1000 / 60)) % 60;
const hours = Math.floor(totalUnits / 1000 / 60 / 60);

const minutesPadded = shorten && hours === 0 ? `${minutes}` : padStart(minutes, 2, '0');

const remainder = totalUnits % unitsPerSec;

// Be nice to filenames and use .
const delim = fileNameFriendly ? '.' : ':';
Expand All @@ -15,21 +28,13 @@ export function formatDuration({ seconds: secondsIn, fileNameFriendly, showMs =
hoursPart = `${hoursPadded}${delim}`;
}

const minutesPadded = shorten && hours === 0 ? `${minutes}` : padStart(minutes, 2, '0');

const secondsAbsFloored = Math.floor(secondsAbs);
const secondsPadded = padStart(secondsAbsFloored % 60, 2, '0');
const ms = secondsAbs - secondsAbsFloored;
let msPart = '';
if (showMs && !(shorten && ms === 0)) {
const msPadded = fps != null
? padStart(Math.round(ms * fps), 2, '0')
: padStart(Math.round(ms * 1000), 3, '0');
msPart = `.${msPadded}`;
let fraction = '';
if (showFraction && !(shorten && remainder === 0)) {
const numDigits = fps != null ? 2 : 3;
fraction = `.${padStart(remainder, numDigits, '0')}`;
}

const sign = secondsIn < 0 ? '-' : '';
return `${sign}${hoursPart}${minutesPadded}${delim}${secondsPadded}${msPart}`;
return `${sign}${hoursPart}${minutesPadded}${delim}${secondsPadded}${fraction}`;
}

export const isExactDurationMatch = (str) => /^-?\d{2}:\d{2}:\d{2}.\d{3}$/.test(str);
Expand Down
15 changes: 13 additions & 2 deletions src/util/duration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ it('should format duration properly', () => {
expect(formatDuration({ seconds: 10000 })).toBe('02:46:40.000');
expect(formatDuration({ seconds: 10000, shorten: true })).toBe('2:46:40');
expect(formatDuration({ seconds: 10000.5, shorten: true })).toBe('2:46:40.500');
expect(formatDuration({ seconds: 101.5, showMs: false })).toBe('00:01:41');
expect(formatDuration({ seconds: 101.5, showMs: false, shorten: true })).toBe('1:41');
expect(formatDuration({ seconds: 101.5, showFraction: false })).toBe('00:01:41');
expect(formatDuration({ seconds: 101.5, showFraction: false, shorten: true })).toBe('1:41');
});

it('should format and parse duration with correct rounding', () => {
Expand All @@ -39,4 +39,15 @@ it('should format and parse duration with correct rounding', () => {
expect(formatDuration({ seconds: parseDuration('1') })).toBe('00:00:01.000');
expect(formatDuration({ seconds: parseDuration('-1') })).toBe('-00:00:01.000');
expect(formatDuration({ seconds: parseDuration('01') })).toBe('00:00:01.000');
expect(formatDuration({ seconds: parseDuration('01:00:00.000') })).toBe('01:00:00.000');
});

it('should handle issue 1603', () => {
expect(formatDuration({ seconds: 1 })).toBe('00:00:01.000');
expect(formatDuration({ seconds: 0.999999 })).toBe('00:00:01.000');
expect(formatDuration({ seconds: 0.999 })).toBe('00:00:00.999');
expect(formatDuration({ seconds: 59.999 })).toBe('00:00:59.999');
expect(formatDuration({ seconds: 59.9999 })).toBe('00:01:00.000');
expect(formatDuration({ seconds: 3599.999 })).toBe('00:59:59.999');
expect(formatDuration({ seconds: 3599.9999 })).toBe('01:00:00.000');
});

0 comments on commit c5fb004

Please sign in to comment.