1/** 2 * Helpers. 3 */ 4 5var s = 1000; 6var m = s * 60; 7var h = m * 60; 8var d = h * 24; 9var w = d * 7; 10var y = d * 365.25; 11 12/** 13 * Parse or format the given `val`. 14 * 15 * Options: 16 * 17 * - `long` verbose formatting [false] 18 * 19 * @param {String|Number} val 20 * @param {Object} [options] 21 * @throws {Error} throw an error if val is not a non-empty string or a number 22 * @return {String|Number} 23 * @api public 24 */ 25 26module.exports = function (val, options) { 27 options = options || {}; 28 var type = typeof val; 29 if (type === 'string' && val.length > 0) { 30 return parse(val); 31 } else if (type === 'number' && isFinite(val)) { 32 return options.long ? fmtLong(val) : fmtShort(val); 33 } 34 throw new Error( 35 'val is not a non-empty string or a valid number. val=' + 36 JSON.stringify(val) 37 ); 38}; 39 40/** 41 * Parse the given `str` and return milliseconds. 42 * 43 * @param {String} str 44 * @return {Number} 45 * @api private 46 */ 47 48function parse(str) { 49 str = String(str); 50 if (str.length > 100) { 51 return; 52 } 53 var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec( 54 str 55 ); 56 if (!match) { 57 return; 58 } 59 var n = parseFloat(match[1]); 60 var type = (match[2] || 'ms').toLowerCase(); 61 switch (type) { 62 case 'years': 63 case 'year': 64 case 'yrs': 65 case 'yr': 66 case 'y': 67 return n * y; 68 case 'weeks': 69 case 'week': 70 case 'w': 71 return n * w; 72 case 'days': 73 case 'day': 74 case 'd': 75 return n * d; 76 case 'hours': 77 case 'hour': 78 case 'hrs': 79 case 'hr': 80 case 'h': 81 return n * h; 82 case 'minutes': 83 case 'minute': 84 case 'mins': 85 case 'min': 86 case 'm': 87 return n * m; 88 case 'seconds': 89 case 'second': 90 case 'secs': 91 case 'sec': 92 case 's': 93 return n * s; 94 case 'milliseconds': 95 case 'millisecond': 96 case 'msecs': 97 case 'msec': 98 case 'ms': 99 return n; 100 default: 101 return undefined; 102 } 103} 104 105/** 106 * Short format for `ms`. 107 * 108 * @param {Number} ms 109 * @return {String} 110 * @api private 111 */ 112 113function fmtShort(ms) { 114 var msAbs = Math.abs(ms); 115 if (msAbs >= d) { 116 return Math.round(ms / d) + 'd'; 117 } 118 if (msAbs >= h) { 119 return Math.round(ms / h) + 'h'; 120 } 121 if (msAbs >= m) { 122 return Math.round(ms / m) + 'm'; 123 } 124 if (msAbs >= s) { 125 return Math.round(ms / s) + 's'; 126 } 127 return ms + 'ms'; 128} 129 130/** 131 * Long format for `ms`. 132 * 133 * @param {Number} ms 134 * @return {String} 135 * @api private 136 */ 137 138function fmtLong(ms) { 139 var msAbs = Math.abs(ms); 140 if (msAbs >= d) { 141 return plural(ms, msAbs, d, 'day'); 142 } 143 if (msAbs >= h) { 144 return plural(ms, msAbs, h, 'hour'); 145 } 146 if (msAbs >= m) { 147 return plural(ms, msAbs, m, 'minute'); 148 } 149 if (msAbs >= s) { 150 return plural(ms, msAbs, s, 'second'); 151 } 152 return ms + ' ms'; 153} 154 155/** 156 * Pluralization helper. 157 */ 158 159function plural(ms, msAbs, n, name) { 160 var isPlural = msAbs >= n * 1.5; 161 return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : ''); 162} 163