1 /**
  2  * Returns a time format of the given type, either "short" or "long".
  3  *
  4  * @class Represents a time format, converting between a <tt>number</tt>
  5  * representing a duration in milliseconds, and a <tt>string</tt>. Two types of
  6  * time formats are supported: "short" and "long". The <i>short</i> format type
  7  * returns a string such as "3.3 days" or "12.1 minutes", while the <i>long</i>
  8  * format returns "13:04:12" or similar.
  9  *
 10  * @extends pv.Format
 11  * @param {string} type the type; "short" or "long".
 12  */
 13 pv.Format.time = function(type) {
 14   var pad = pv.Format.pad;
 15 
 16   /*
 17    * MILLISECONDS = 1
 18    * SECONDS = 1e3
 19    * MINUTES = 6e4
 20    * HOURS = 36e5
 21    * DAYS = 864e5
 22    * WEEKS = 6048e5
 23    * MONTHS = 2592e6
 24    * YEARS = 31536e6
 25    */
 26 
 27   /** @private */
 28   function format(t) {
 29     t = Number(t); // force conversion from Date
 30     switch (type) {
 31       case "short": {
 32         if (t >= 31536e6) {
 33           return (t / 31536e6).toFixed(1) + " years";
 34         } else if (t >= 6048e5) {
 35           return (t / 6048e5).toFixed(1) + " weeks";
 36         } else if (t >= 864e5) {
 37           return (t / 864e5).toFixed(1) + " days";
 38         } else if (t >= 36e5) {
 39           return (t / 36e5).toFixed(1) + " hours";
 40         } else if (t >= 6e4) {
 41           return (t / 6e4).toFixed(1) + " minutes";
 42         }
 43         return (t / 1e3).toFixed(1) + " seconds";
 44       }
 45       case "long": {
 46         var a = [],
 47             s = ((t % 6e4) / 1e3) >> 0,
 48             m = ((t % 36e5) / 6e4) >> 0;
 49         a.push(pad("0", 2, s));
 50         if (t >= 36e5) {
 51           var h = ((t % 864e5) / 36e5) >> 0;
 52           a.push(pad("0", 2, m));
 53           if (t >= 864e5) {
 54             a.push(pad("0", 2, h));
 55             a.push(Math.floor(t / 864e5).toFixed());
 56           } else {
 57             a.push(h.toFixed());
 58           }
 59         } else {
 60           a.push(m.toFixed());
 61         }
 62         return a.reverse().join(":");
 63       }
 64     }
 65   }
 66 
 67   /**
 68    * Formats the specified time, returning the string representation.
 69    *
 70    * @function
 71    * @name pv.Format.time.prototype.format
 72    * @param {number} t the duration in milliseconds. May also be a <tt>Date</tt>.
 73    * @returns {string} the formatted string.
 74    */
 75   format.format = format;
 76 
 77   /**
 78    * Parses the specified string, returning the time in milliseconds.
 79    *
 80    * @function
 81    * @name pv.Format.time.prototype.parse
 82    * @param {string} s a formatted string.
 83    * @returns {number} the parsed duration in milliseconds.
 84    */
 85   format.parse = function(s) {
 86     switch (type) {
 87       case "short": {
 88         var re = /([0-9,.]+)\s*([a-z]+)/g, a, t = 0;
 89         while (a = re.exec(s)) {
 90           var f = parseFloat(a[0].replace(",", "")), u = 0;
 91           switch (a[2].toLowerCase()) {
 92             case "year": case "years": u = 31536e6; break;
 93             case "week": case "weeks": u = 6048e5; break;
 94             case "day": case "days": u = 864e5; break;
 95             case "hour": case "hours": u = 36e5; break;
 96             case "minute": case "minutes": u = 6e4; break;
 97             case "second": case "seconds": u = 1e3; break;
 98           }
 99           t += f * u;
100         }
101         return t;
102       }
103       case "long": {
104         var a = s.replace(",", "").split(":").reverse(), t = 0;
105         if (a.length) t += parseFloat(a[0]) * 1e3;
106         if (a.length > 1) t += parseFloat(a[1]) * 6e4;
107         if (a.length > 2) t += parseFloat(a[2]) * 36e5;
108         if (a.length > 3) t += parseFloat(a[3]) * 864e5;
109         return t;
110       }
111     }
112   }
113 
114   return format;
115 };
116