Skip to content

Commit

Permalink
feat: add duration helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
altaywtf committed Oct 25, 2023
1 parent baa40e7 commit f61c421
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 0 deletions.
57 changes: 57 additions & 0 deletions src/date/duration.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { secondsToDuration, secondsToReadableDuration } from './duration';

describe('duration', () => {
describe('secondsToDuration', () => {
it('handles null input', () => {
expect(secondsToDuration(null)).toBe('00:00');
});

it('formats seconds as mm:ss', () => {
expect(secondsToDuration(4)).toBe('00:04');
expect(secondsToDuration(44)).toBe('00:44');
});

it('formats minutes as mm:ss', () => {
expect(secondsToDuration(444)).toBe('07:24');
});

it('formats hours as HH:mm:ss', () => {
expect(secondsToDuration(44444)).toBe('12:20:44');
});

it('formats hours (more than 24) as dd:HH:mm:ss', () => {
expect(secondsToDuration(444444)).toBe('05:03:27:24');
});

it('handles decimal duration inputs', () => {
expect(secondsToDuration(2565.568)).toBe('42:45');
});
});

describe('secondsToReadableDuration', () => {
it('handles null input', () => {
expect(secondsToDuration(null)).toBe('00:00');
});

it('formats seconds as s', () => {
expect(secondsToReadableDuration(4)).toBe('4 s');
expect(secondsToReadableDuration(44)).toBe('44 s');
});

it('formats minutes as mm ss', () => {
expect(secondsToReadableDuration(444)).toBe('7m 24s');
});

it('formats hours as HH mm', () => {
expect(secondsToReadableDuration(44444)).toBe('12h 21m');
});

it('formats hours (more than 24) as dd HH', () => {
expect(secondsToReadableDuration(444444)).toBe('5d 3h');
});

it('handles decimal duration inputs', () => {
expect(secondsToReadableDuration(2565.568)).toBe('43m');
});
});
});
78 changes: 78 additions & 0 deletions src/date/duration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
const ensureNumber = (value: number | unknown) => {
if (typeof value !== 'number') {
return 0;
}

return value;
};

export const secondsToDuration = (seconds: number | unknown) => {
const normalizedSeconds = Math.floor(ensureNumber(seconds));

if (normalizedSeconds <= 0) {
return '00:00';
}

const days = Math.floor(normalizedSeconds / (60 * 60 * 24));
const minutes = Math.floor(normalizedSeconds / 60) % 60;
let hours = Math.floor(normalizedSeconds / (60 * 60));

if (days) {
hours = Math.round((normalizedSeconds - days * (60 * 60 * 24)) / 60 / 60);

return [days, hours, minutes, normalizedSeconds % 60]
.map((v) => (v < 10 ? `0${v}` : v))
.filter((v, i) => v !== '00' || i > 0)
.join(':');
}

return [hours, minutes, normalizedSeconds % 60]
.map((v) => (v < 10 ? `0${v}` : v))
.filter((v, i) => v !== '00' || i > 0)
.join(':');
};

export const secondsToReadableDuration = (seconds: number | unknown) => {
const normalizedSeconds = Math.floor(ensureNumber(seconds));

if (normalizedSeconds <= 0) {
return '';
}

const fSec = 's';
const fMin = 'm';
const fHour = 'h';
const fDay = 'd';

if (normalizedSeconds < 60) {
return `${seconds} ${fSec}`;
}

if (normalizedSeconds > 60 * 60 * 24) {
const days = Math.floor(normalizedSeconds / (60 * 60 * 24));
const hour = Math.round(
(normalizedSeconds - days * (60 * 60 * 24)) / 60 / 60
);
return `${days}${fDay}${hour > 0 ? ` ${hour}${fHour}` : ''}`;
}

if (normalizedSeconds >= 60 * 60) {
const hour = Math.floor(normalizedSeconds / (60 * 60));
const m = Math.round((normalizedSeconds - hour * 60 * 60) / 60);
let mins = '';

if (m > 0) {
mins = ` ${m}${fMin}`;
}

return `${hour}${fHour}${mins}`;
}

if (normalizedSeconds > 60) {
const m = Math.round(normalizedSeconds / 60);
const sec = normalizedSeconds - m * 60;
const secText = sec > 0 ? ` ${sec}${fSec}` : '';

return `${m}${fMin}${secText}`;
}
};
2 changes: 2 additions & 0 deletions src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ describe('lib', () => {
"formatDate": [Function],
"getUnixTimestamp": [Function],
"isErrorLocalizer": [Function],
"secondsToDuration": [Function],
"secondsToReadableDuration": [Function],
"toHumanFileSize": [Function],
"toTimeAgo": [Function],
}
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { default as ExtendableError } from 'es6-error';
export * from './date/date';
export * from './date/duration';
export * from './errors';
export * from './file/file';
export * from './localized-error/LocalizedError';
Expand Down

0 comments on commit f61c421

Please sign in to comment.