1 /** 2 * Constructs a new date format with the specified string pattern. 3 * 4 * @class The format string is in the same format expected by the 5 * <tt>strftime</tt> function in C. The following conversion specifications are 6 * supported:<ul> 7 * 8 * <li>%a - abbreviated weekday name.</li> 9 * <li>%A - full weekday name.</li> 10 * <li>%b - abbreviated month names.</li> 11 * <li>%B - full month names.</li> 12 * <li>%c - locale's appropriate date and time.</li> 13 * <li>%C - century number.</li> 14 * <li>%d - day of month [01,31] (zero padded).</li> 15 * <li>%D - same as %m/%d/%y.</li> 16 * <li>%e - day of month [ 1,31] (space padded).</li> 17 * <li>%h - same as %b.</li> 18 * <li>%H - hour (24-hour clock) [00,23] (zero padded).</li> 19 * <li>%I - hour (12-hour clock) [01,12] (zero padded).</li> 20 * <li>%m - month number [01,12] (zero padded).</li> 21 * <li>%M - minute [0,59] (zero padded).</li> 22 * <li>%n - newline character.</li> 23 * <li>%p - locale's equivalent of a.m. or p.m.</li> 24 * <li>%r - same as %I:%M:%S %p.</li> 25 * <li>%R - same as %H:%M.</li> 26 * <li>%S - second [00,61] (zero padded).</li> 27 * <li>%t - tab character.</li> 28 * <li>%T - same as %H:%M:%S.</li> 29 * <li>%x - same as %m/%d/%y.</li> 30 * <li>%X - same as %I:%M:%S %p.</li> 31 * <li>%y - year with century [00,99] (zero padded).</li> 32 * <li>%Y - year including century.</li> 33 * <li>%% - %.</li> 34 * 35 * </ul>The following conversion specifications are currently <i>unsupported</i> 36 * for formatting:<ul> 37 * 38 * <li>%j - day number [1,366].</li> 39 * <li>%u - weekday number [1,7].</li> 40 * <li>%U - week number [00,53].</li> 41 * <li>%V - week number [01,53].</li> 42 * <li>%w - weekday number [0,6].</li> 43 * <li>%W - week number [00,53].</li> 44 * <li>%Z - timezone name or abbreviation.</li> 45 * 46 * </ul>In addition, the following conversion specifications are currently 47 * <i>unsupported</i> for parsing:<ul> 48 * 49 * <li>%a - day of week, either abbreviated or full name.</li> 50 * <li>%A - same as %a.</li> 51 * <li>%c - locale's appropriate date and time.</li> 52 * <li>%C - century number.</li> 53 * <li>%D - same as %m/%d/%y.</li> 54 * <li>%I - hour (12-hour clock) [1,12].</li> 55 * <li>%n - any white space.</li> 56 * <li>%p - locale's equivalent of a.m. or p.m.</li> 57 * <li>%r - same as %I:%M:%S %p.</li> 58 * <li>%R - same as %H:%M.</li> 59 * <li>%t - same as %n.</li> 60 * <li>%T - same as %H:%M:%S.</li> 61 * <li>%x - locale's equivalent to %m/%d/%y.</li> 62 * <li>%X - locale's equivalent to %I:%M:%S %p.</li> 63 * 64 * </ul> 65 * 66 * @see <a 67 * href="http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html">strftime</a> 68 * documentation. 69 * @see <a 70 * href="http://www.opengroup.org/onlinepubs/007908799/xsh/strptime.html">strptime</a> 71 * documentation. 72 * @extends pv.Format 73 * @param {string} pattern the format pattern. 74 */ 75 pv.Format.date = function(pattern) { 76 var pad = pv.Format.pad; 77 78 /** @private */ 79 function format(d) { 80 return pattern.replace(/%[a-zA-Z0-9]/g, function(s) { 81 switch (s) { 82 case '%a': return [ 83 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 84 ][d.getDay()]; 85 case '%A': return [ 86 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", 87 "Saturday" 88 ][d.getDay()]; 89 case '%h': 90 case '%b': return [ 91 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", 92 "Oct", "Nov", "Dec" 93 ][d.getMonth()]; 94 case '%B': return [ 95 "January", "February", "March", "April", "May", "June", "July", 96 "August", "September", "October", "November", "December" 97 ][d.getMonth()]; 98 case '%c': return d.toLocaleString(); 99 case '%C': return pad("0", 2, Math.floor(d.getFullYear() / 100) % 100); 100 case '%d': return pad("0", 2, d.getDate()); 101 case '%x': 102 case '%D': return pad("0", 2, d.getMonth() + 1) 103 + "/" + pad("0", 2, d.getDate()) 104 + "/" + pad("0", 2, d.getFullYear() % 100); 105 case '%e': return pad(" ", 2, d.getDate()); 106 case '%H': return pad("0", 2, d.getHours()); 107 case '%I': { 108 var h = d.getHours() % 12; 109 return h ? pad("0", 2, h) : 12; 110 } 111 // TODO %j: day of year as a decimal number [001,366] 112 case '%m': return pad("0", 2, d.getMonth() + 1); 113 case '%M': return pad("0", 2, d.getMinutes()); 114 case '%n': return "\n"; 115 case '%p': return d.getHours() < 12 ? "AM" : "PM"; 116 case '%T': 117 case '%X': 118 case '%r': { 119 var h = d.getHours() % 12; 120 return (h ? pad("0", 2, h) : 12) 121 + ":" + pad("0", 2, d.getMinutes()) 122 + ":" + pad("0", 2, d.getSeconds()) 123 + " " + (d.getHours() < 12 ? "AM" : "PM"); 124 } 125 case '%R': return pad("0", 2, d.getHours()) + ":" + pad("0", 2, d.getMinutes()); 126 case '%S': return pad("0", 2, d.getSeconds()); 127 case '%Q': return pad("0", 3, d.getMilliseconds()); 128 case '%t': return "\t"; 129 case '%u': { 130 var w = d.getDay(); 131 return w ? w : 1; 132 } 133 // TODO %U: week number (sunday first day) [00,53] 134 // TODO %V: week number (monday first day) [01,53] ... with weirdness 135 case '%w': return d.getDay(); 136 // TODO %W: week number (monday first day) [00,53] ... with weirdness 137 case '%y': return pad("0", 2, d.getFullYear() % 100); 138 case '%Y': return d.getFullYear(); 139 // TODO %Z: timezone name or abbreviation 140 case '%%': return "%"; 141 } 142 return s; 143 }); 144 } 145 146 /** 147 * Converts a date to a string using the associated formatting pattern. 148 * 149 * @function 150 * @name pv.Format.date.prototype.format 151 * @param {Date} date a date to format. 152 * @returns {string} the formatted date as a string. 153 */ 154 format.format = format; 155 156 /** 157 * Parses a date from a string using the associated formatting pattern. 158 * 159 * @function 160 * @name pv.Format.date.prototype.parse 161 * @param {string} s the string to parse as a date. 162 * @returns {Date} the parsed date. 163 */ 164 format.parse = function(s) { 165 var year = 1970, month = 0, date = 1, hour = 0, minute = 0, second = 0; 166 var fields = [function() {}]; 167 168 /* Register callbacks for each field in the format pattern. */ 169 var re = pv.Format.re(pattern).replace(/%[a-zA-Z0-9]/g, function(s) { 170 switch (s) { 171 // TODO %a: day of week, either abbreviated or full name 172 // TODO %A: same as %a 173 case '%b': { 174 fields.push(function(x) { month = { 175 Jan: 0, Feb: 1, Mar: 2, Apr: 3, May: 4, Jun: 5, Jul: 6, Aug: 7, 176 Sep: 8, Oct: 9, Nov: 10, Dec: 11 177 }[x]; }); 178 return "([A-Za-z]+)"; 179 } 180 case '%h': 181 case '%B': { 182 fields.push(function(x) { month = { 183 January: 0, February: 1, March: 2, April: 3, May: 4, June: 5, 184 July: 6, August: 7, September: 8, October: 9, November: 10, 185 December: 11 186 }[x]; }); 187 return "([A-Za-z]+)"; 188 } 189 // TODO %c: locale's appropriate date and time 190 // TODO %C: century number[0,99] 191 case '%e': 192 case '%d': { 193 fields.push(function(x) { date = x; }); 194 return "([0-9]+)"; 195 } 196 // TODO %D: same as %m/%d/%y 197 case '%I': 198 case '%H': { 199 fields.push(function(x) { hour = x; }); 200 return "([0-9]+)"; 201 } 202 // TODO %j: day number [1,366] 203 case '%m': { 204 fields.push(function(x) { month = x - 1; }); 205 return "([0-9]+)"; 206 } 207 case '%M': { 208 fields.push(function(x) { minute = x; }); 209 return "([0-9]+)"; 210 } 211 // TODO %n: any white space 212 // TODO %p: locale's equivalent of a.m. or p.m. 213 case '%p': { // TODO this is a hack 214 fields.push(function(x) { 215 if (hour == 12) { 216 if (x == "am") hour = 0; 217 } else if (x == "pm") { 218 hour = Number(hour) + 12; 219 } 220 }); 221 return "(am|pm)"; 222 } 223 // TODO %r: %I:%M:%S %p 224 // TODO %R: %H:%M 225 case '%S': { 226 fields.push(function(x) { second = x; }); 227 return "([0-9]+)"; 228 } 229 // TODO %t: any white space 230 // TODO %T: %H:%M:%S 231 // TODO %U: week number [00,53] 232 // TODO %w: weekday [0,6] 233 // TODO %W: week number [00, 53] 234 // TODO %x: locale date (%m/%d/%y) 235 // TODO %X: locale time (%I:%M:%S %p) 236 case '%y': { 237 fields.push(function(x) { 238 x = Number(x); 239 year = x + (((0 <= x) && (x < 69)) ? 2000 240 : (((x >= 69) && (x < 100) ? 1900 : 0))); 241 }); 242 return "([0-9]+)"; 243 } 244 case '%Y': { 245 fields.push(function(x) { year = x; }); 246 return "([0-9]+)"; 247 } 248 case '%%': { 249 fields.push(function() {}); 250 return "%"; 251 } 252 } 253 return s; 254 }); 255 256 var match = s.match(re); 257 if (match) match.forEach(function(m, i) { fields[i](m); }); 258 return new Date(year, month, date, hour, minute, second); 259 }; 260 261 return format; 262 }; 263