index.js 3.0 KB

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