es6/utils/Time.js
/**
* A collection of Time utils to make working with Time a little easier in Javascript
* Have care with delays larger than 2147483647 milliseconds (approximately 25 days) or less than 1.
*
* @namespace Time
*/
/**
* different millisecond time intervals
*
* @type {Object}
* @property {Integer} second number of milliseconds in a second
* @property {Integer} minutes number of milliseconds in a minute
* @property {Integer} hour number of milliseconds in a hour
* @property {Integer} day number of milliseconds in a day
*/
export const EPOCS = {}
EPOCS.second = 1000
EPOCS.minute = 60 * EPOCS.second
EPOCS.hour = EPOCS.minute * 60
EPOCS.day = EPOCS.hour * 24
/**
* returns a humanized time representation of the difference between two millisecond dates
*
* @function humanize
* @memberof Time
* @param {Integer} start the start date in number of milliseconds since 1 January, 1970 UTC
* @param {Integer} [Date.now()] end the end date in number of milliseconds
* @return {Object}
*/
export function humanize ( start, end=Date.now() ) {
let diff = end - start
const days = Math.floor( diff / EPOCS.day )
diff = diff % EPOCS.day
const hours = Math.floor( diff / EPOCS.hour )
diff = diff % EPOCS.hour
const minutes = Math.floor( diff / EPOCS.minute )
diff = diff % EPOCS.minute
const seconds = Math.floor(diff / EPOCS.second ) || 0
return {
days : days
, hours : hours
, minutes : minutes
, seconds : seconds
}
}
/**
* returns how many seconds have elapsed since `n` compared to `Date.now()`
*
* @function secondsAgo
* @memberof Time
* @param {Integer} n the start date in milliseconds
* @return {Integer} the number of seconds that have elapsed
*/
export function secondsAgo (n) {
return Date.now() - EPOCS.second * n
}
/**
* returns `n` number of seconds converted to milliseconds
*
* @function seconds
* @memberof Time
* @param {Integer} n the number of seconds
* @return {Integer}
*
* @example
*
* seconds(2) // 2000
*/
export function seconds (n) {
return EPOCS.second * n
}
/**
* returns `n` number of minutes converted to milliseconds
*
* @function minutes
* @memberof Time
* @param {Integer} n the number of minutes
* @return {Integer}
*
* @example
*
* minutes(1) // 1000 * 60
*/
export function minutes (n) {
return EPOCS.minute * n
}
/**
* returns `n` number of hours converted to milliseconds
*
* @function hours
* @memberof Time
* @param {Integer} n the number of hours
* @return {Integer}
*
* @example
*
* hours(1) // 1000 * 60 * 60
*/
export function hours (n) {
return EPOCS.hour * n
}
/**
* returns `n` number of days converted to milliseconds.
*
* @function days
* @memberof Time
* @param {Integer} n the number of days
* @return {Integer}
*
* @example
*
* days(1) // 1000 * 60 * 60 * 24
*/
export function days (n) {
return EPOCS.day * n
}
/**
* compares a Date Object to a millisecond representation
*
* @function olderThan
* @memberof Time
* @param {Date} date a Date object
* @param {Integer} milliDate a millisecond representation of a Date
*
* @returns {Boolean} whether date is older than milliDate
*/
export function olderThan (date, milliDate) {
return (new Date(date)).getTime() < milliDate
}
/**
* used for making sure a code block runs within a certain amount of time
*
* @class Timer
*
*/
export class Timer {
/**
* creates a new Timer
*
* @method create
* @param {Object} config The config object
* @param {String} config.name [__filename where Timer is created] The name of the Timer (for errors)
* @param {Integer} config.max_run_time [1 minute] The max run time in milliseconds
* @param {Function} config.after [Timer.prototype.error] The function to run after a Timer ends
*/
static create (config) {
config.name = config.name || (new Error()).stack.split("\n")[2].split(" at ")[1]
return new Timer(config)
}
/**
* constructor
*
* @method constructor
* @param {Object} config The config
*/
constructor (config) {
this.name = config.name
this.onEnd = config.after || this.error.bind(this, `${this.name} expired without an after effect`)
this.runtime = config.max_run_time || minutes(1)
this.touches = 0
return this.begin()
}
/**
* Throws a Timer Error
*
* @method error
* @param {<type>} msg The error message
*/
error (msg) {
throw new Error(msg)
}
/**
* Restarts a Timer's clock
*
* @method touch
* @return this
*/
touch () {
this.touches++
this.cancel()
return this.begin()
}
/**
* convenience method to begin a Timer
*
* @method begin
* @return this
*/
begin () {
const timer = this
// prevent creating unreachable Timeouts
if (timer.$ && timer.$._onTimeout) {
return timer
}
timer.$ = setTimeout( function interrupt () { timer.onEnd(timer) }, timer.runtime)
return timer
}
/**
* cancels a Timer so it will not throw
*
* @method cancel
*/
cancel () {
clearTimeout(this.$)
return this
}
}