Skip to content

Instantly share code, notes, and snippets.

@martin-sweeny
Last active October 21, 2020 08:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martin-sweeny/ecdaba464b8a3e50793af1aa2aae2701 to your computer and use it in GitHub Desktop.
Save martin-sweeny/ecdaba464b8a3e50793af1aa2aae2701 to your computer and use it in GitHub Desktop.
/**
* @typedef {TimeUnitTuple[]} TimeUnitTable A table of time units (seconds, minutes, for example), with their corresponding multipliers compared to the last value. The order is important, as each tuple contains a `multiplier`, which is how many times the last value would fit into this one (i.e. there are 60 minutes in an hour, so hour would be [60, 'hours'])
* @typedef {[multiplier: number, label: string]} TimeUnitTuple Intended to be used in an array of the same type, where the `multiplier` represents how many times this unit fits into the last, and `label` is the name of that unit (for example, days)
*/
/**
* Returns the absolute difference between two date objects
* @curried
* @param {(number | Date)} date1
* @returns {(date2?: number | Date) => number} The difference in milliseconds
* @example
* // returns 1008823000
* getTimeDifference
* (new Date("October 12 2020 16:00:00"))
* (new Date("October 24 2020 08:13:43"));
* @example <caption>The function can take 1 date to get the difference between then and now</caption>
* // (Assuming that the current date is October 24 2020 08:13:43)
* // returns 1008823000
* getTimeDifference(new Date("October 12 2020 16:00:00"))();
*/
const getTimeDifference = (date1) => (date2 = new Date().getTime()) =>
Math.abs(date2 - date1);
/**
* Translates an amount of milliseconds into a human readable form
* @param {number} ms
* @returns {string} A human readable string, including (if necessary) days, hours, minutes, and seconds
* @example
* // returns '11 days 16 hours 13 minutes 43 seconds'
* const diff = toHumanReadable(1008823000);
*/
const toHumanReadable = (ms) => {
/**
* @type TimeUnitTable
*/
const unitMap = [
[1000, "seconds"],
[60, "minutes"],
[60, "hours"],
[24, "days"],
];
/**
* Loops through unitMap, multiplying the numbers to get the total amount of milliseconds to divide by
* @param {number} index The index to start at
*/
const getDivisor = (index) =>
unitMap.slice(index).reduce((prev, [curr]) => prev * curr, 1);
/**
* Loops through unitMap, using the tuples to divide the remaining ms and labeling the step with the appropriate unit
* @param {number} ms
* @returns {[string, number]} The text and remaining milliseconds
*/
const getTimeRemaining = (ms) =>
unitMap.reverse().reduce(
([text, time], [, unitText], i) => {
const divisor = getDivisor(i);
const dividend = time / divisor;
const remainder = time % divisor;
return dividend > 1
? [`${text} ${Math.floor(dividend)} ${unitText}`, remainder]
: [text, time];
},
["", ms]
);
// Let's return only the text
return getTimeRemaining(ms)[0];
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment