-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(duration): expose get duration procedure
- Loading branch information
1 parent
191a0ab
commit 87b9d7b
Showing
12 changed files
with
312 additions
and
22 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import { given, then, when } from 'test-fns'; | ||
|
||
import { asUniDateTime } from '../checks/isUniDateTime'; | ||
import { getDuration } from './getDuration'; | ||
import { | ||
MILLISECONDS_PER_DAY, | ||
MILLISECONDS_PER_HOUR, | ||
MILLISECONDS_PER_WEEK, | ||
} from './toMilliseconds'; | ||
|
||
describe('getDuration', () => { | ||
given('milliseconds', () => { | ||
when('less than a second', () => { | ||
then('it should accurately define the duration', () => { | ||
const duration = getDuration({ of: { milliseconds: 69 } }); | ||
expect(duration).toEqual({ milliseconds: 69 }); | ||
}); | ||
}); | ||
when('less than a minute', () => { | ||
then('it should accurately define the duration', () => { | ||
const duration = getDuration({ of: { milliseconds: 1069 } }); | ||
expect(duration).toEqual({ seconds: 1, milliseconds: 69 }); | ||
}); | ||
}); | ||
when('less than an day', () => { | ||
then('it should accurately define the duration', () => { | ||
const duration = getDuration({ | ||
of: { milliseconds: 7 * MILLISECONDS_PER_HOUR + 1069 }, | ||
}); | ||
expect(duration).toEqual({ hours: 7, seconds: 1, milliseconds: 69 }); | ||
}); | ||
}); | ||
when('less than a week', () => { | ||
then('it should accurately define the duration', () => { | ||
const duration = getDuration({ | ||
of: { | ||
milliseconds: | ||
3 * MILLISECONDS_PER_DAY + 7 * MILLISECONDS_PER_HOUR + 1069, | ||
}, | ||
}); | ||
expect(duration).toEqual({ | ||
days: 3, | ||
hours: 7, | ||
seconds: 1, | ||
milliseconds: 69, | ||
}); | ||
}); | ||
}); | ||
when('less than a month ', () => { | ||
then('it should accurately define the duration', () => { | ||
const duration = getDuration({ | ||
of: { | ||
milliseconds: | ||
5 * MILLISECONDS_PER_WEEK + | ||
3 * MILLISECONDS_PER_DAY + | ||
7 * MILLISECONDS_PER_HOUR + | ||
1069, | ||
}, | ||
}); | ||
expect(duration).toEqual({ | ||
weeks: 5, | ||
days: 3, | ||
hours: 7, | ||
seconds: 1, | ||
milliseconds: 69, | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
given('range', () => { | ||
when('has parts of each time unit', () => { | ||
then('it should accurately define the duration', () => { | ||
const duration = getDuration({ | ||
of: { | ||
range: { | ||
since: asUniDateTime('2024-09-09T13:08:21.4269Z'), | ||
until: asUniDateTime('2024-09-17T15:53:31.3157Z'), | ||
}, | ||
}, | ||
}); | ||
expect(duration).toEqual({ | ||
weeks: 1, | ||
days: 1, | ||
hours: 2, | ||
minutes: 45, | ||
seconds: 9, | ||
milliseconds: 889, | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
given('a unit to get the duration in', () => { | ||
when('asked to define it in seconds', () => { | ||
then('it should accurately define the duration', () => { | ||
const duration = getDuration({ | ||
of: { | ||
range: { | ||
since: asUniDateTime('2024-09-09T13:08:21.4269Z'), | ||
until: asUniDateTime('2024-09-17T15:53:31.3157Z'), | ||
}, | ||
}, | ||
as: 'seconds', | ||
}); | ||
expect(duration).toEqual({ | ||
seconds: 701109.889, | ||
}); | ||
}); | ||
}); | ||
when('asked to define it in seconds', () => { | ||
then('it should accurately define the duration', () => { | ||
const duration = getDuration({ | ||
of: { | ||
range: { | ||
since: asUniDateTime('2024-09-09T13:08:21.4269Z'), | ||
until: asUniDateTime('2024-09-17T15:53:31.3157Z'), | ||
}, | ||
}, | ||
as: 'minutes', | ||
}); | ||
expect(duration).toEqual({ | ||
minutes: 11685.164816666667, | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { UnexpectedCodePathError } from '@ehmpathy/error-fns'; | ||
import { PickOne } from 'type-fns'; | ||
|
||
import { UniDateTimeRange } from '../../domain/UniDateTime'; | ||
import { UniDuration } from '../../domain/UniDuration'; | ||
import { toMse } from '../casts/toMillisecondsSinceEpoch'; | ||
import { | ||
MILLISECONDS_PER_DAY, | ||
MILLISECONDS_PER_HOUR, | ||
MILLISECONDS_PER_MINUTE, | ||
MILLISECONDS_PER_SECOND, | ||
MILLISECONDS_PER_WEEK, | ||
} from './toMilliseconds'; | ||
|
||
/** | ||
* .what = calculates the duration of a time range | ||
*/ | ||
export const getDuration = (input: { | ||
/** | ||
* what measure of time to extract a duration from | ||
*/ | ||
of: PickOne<{ range: UniDateTimeRange; milliseconds: number }>; | ||
|
||
/** | ||
* the unit to define the duration in, if desired | ||
* | ||
* note | ||
* - by default, it will define it via all of them | ||
*/ | ||
as?: keyof UniDuration; | ||
}): UniDuration => { | ||
// handle range inputs | ||
if (input.of.range) | ||
return getDuration({ | ||
of: { | ||
milliseconds: toMse(input.of.range.until) - toMse(input.of.range.since), | ||
}, | ||
as: input.as, | ||
}); | ||
|
||
// handle milliseconds | ||
if (input.of.milliseconds) { | ||
// if asked to define in a specific unit, define it in that unit | ||
if (input.as) { | ||
if (input.as === 'weeks') | ||
return { weeks: input.of.milliseconds / MILLISECONDS_PER_WEEK }; | ||
if (input.as === 'days') | ||
return { days: input.of.milliseconds / MILLISECONDS_PER_DAY }; | ||
if (input.as === 'hours') | ||
return { hours: input.of.milliseconds / MILLISECONDS_PER_HOUR }; | ||
if (input.as === 'minutes') | ||
return { minutes: input.of.milliseconds / MILLISECONDS_PER_MINUTE }; | ||
if (input.as === 'seconds') | ||
return { seconds: input.of.milliseconds / MILLISECONDS_PER_SECOND }; | ||
if (input.as === 'milliseconds') | ||
return { milliseconds: input.of.milliseconds }; | ||
throw new UnexpectedCodePathError( | ||
'input.as does not specify a valid unit', | ||
{ input }, | ||
); | ||
} | ||
|
||
// otherwise, define it via all of the units | ||
const weeks = Math.floor(input.of.milliseconds / MILLISECONDS_PER_WEEK); | ||
const days = Math.floor( | ||
(input.of.milliseconds % MILLISECONDS_PER_WEEK) / MILLISECONDS_PER_DAY, | ||
); | ||
const hours = Math.floor( | ||
(input.of.milliseconds % MILLISECONDS_PER_DAY) / MILLISECONDS_PER_HOUR, | ||
); | ||
const minutes = Math.floor( | ||
(input.of.milliseconds % MILLISECONDS_PER_HOUR) / MILLISECONDS_PER_MINUTE, | ||
); | ||
const seconds = Math.floor( | ||
(input.of.milliseconds % MILLISECONDS_PER_MINUTE) / | ||
MILLISECONDS_PER_SECOND, | ||
); | ||
const milliseconds = input.of.milliseconds % MILLISECONDS_PER_SECOND; | ||
const durationWithRedundantZeros = { | ||
weeks, | ||
days, | ||
hours, | ||
minutes, | ||
seconds, | ||
milliseconds, | ||
}; | ||
const duration = Object.fromEntries( | ||
Object.entries(durationWithRedundantZeros).filter( | ||
([key, val]) => val > 0, | ||
), | ||
) as any as UniDuration; | ||
return duration; | ||
} | ||
|
||
// otherwise, unsupported | ||
throw new UnexpectedCodePathError('input.of choice is not supported', { | ||
input, | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { UniDuration } from '../../domain/UniDuration'; | ||
|
||
export const DAYS_PER_WEEK = 7; | ||
export const HOURS_PER_DAY = 24; | ||
export const MINUTES_PER_HOUR = 60; | ||
export const SECONDS_PER_MINUTE = 60; | ||
export const MILLISECONDS_PER_SECOND = 1000; | ||
export const MILLISECONDS_PER_MINUTE = | ||
MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE; | ||
export const MILLISECONDS_PER_HOUR = MILLISECONDS_PER_MINUTE * MINUTES_PER_HOUR; | ||
export const MILLISECONDS_PER_DAY = MILLISECONDS_PER_HOUR * HOURS_PER_DAY; | ||
export const MILLISECONDS_PER_WEEK = MILLISECONDS_PER_DAY * DAYS_PER_WEEK; | ||
|
||
export const toMilliseconds = (duration: UniDuration): number => { | ||
const total = [ | ||
(duration.weeks ?? 0) * MILLISECONDS_PER_WEEK, | ||
(duration.days ?? 0) * MILLISECONDS_PER_DAY, | ||
(duration.hours ?? 0) * MILLISECONDS_PER_HOUR, | ||
(duration.minutes ?? 0) * MILLISECONDS_PER_MINUTE, | ||
(duration.seconds ?? 0) * MILLISECONDS_PER_SECOND, | ||
duration.milliseconds ?? 0, | ||
].reduce((totalNow, thisMilliseconds) => totalNow + thisMilliseconds, 0); | ||
return total; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.