[76] | 1 | /*! |
---|
| 2 | * Ext JS Library 3.4.0 |
---|
| 3 | * Copyright(c) 2006-2011 Sencha Inc. |
---|
| 4 | * licensing@sencha.com |
---|
| 5 | * http://www.sencha.com/license |
---|
| 6 | */ |
---|
| 7 | /** |
---|
| 8 | * @class Date |
---|
| 9 | * |
---|
| 10 | * The date parsing and formatting syntax contains a subset of |
---|
| 11 | * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are |
---|
| 12 | * supported will provide results equivalent to their PHP versions. |
---|
| 13 | * |
---|
| 14 | * The following is a list of all currently supported formats: |
---|
| 15 | * <pre> |
---|
| 16 | Format Description Example returned values |
---|
| 17 | ------ ----------------------------------------------------------------------- ----------------------- |
---|
| 18 | d Day of the month, 2 digits with leading zeros 01 to 31 |
---|
| 19 | D A short textual representation of the day of the week Mon to Sun |
---|
| 20 | j Day of the month without leading zeros 1 to 31 |
---|
| 21 | l A full textual representation of the day of the week Sunday to Saturday |
---|
| 22 | N ISO-8601 numeric representation of the day of the week 1 (for Monday) through 7 (for Sunday) |
---|
| 23 | S English ordinal suffix for the day of the month, 2 characters st, nd, rd or th. Works well with j |
---|
| 24 | w Numeric representation of the day of the week 0 (for Sunday) to 6 (for Saturday) |
---|
| 25 | z The day of the year (starting from 0) 0 to 364 (365 in leap years) |
---|
| 26 | W ISO-8601 week number of year, weeks starting on Monday 01 to 53 |
---|
| 27 | F A full textual representation of a month, such as January or March January to December |
---|
| 28 | m Numeric representation of a month, with leading zeros 01 to 12 |
---|
| 29 | M A short textual representation of a month Jan to Dec |
---|
| 30 | n Numeric representation of a month, without leading zeros 1 to 12 |
---|
| 31 | t Number of days in the given month 28 to 31 |
---|
| 32 | L Whether it's a leap year 1 if it is a leap year, 0 otherwise. |
---|
| 33 | o ISO-8601 year number (identical to (Y), but if the ISO week number (W) Examples: 1998 or 2004 |
---|
| 34 | belongs to the previous or next year, that year is used instead) |
---|
| 35 | Y A full numeric representation of a year, 4 digits Examples: 1999 or 2003 |
---|
| 36 | y A two digit representation of a year Examples: 99 or 03 |
---|
| 37 | a Lowercase Ante meridiem and Post meridiem am or pm |
---|
| 38 | A Uppercase Ante meridiem and Post meridiem AM or PM |
---|
| 39 | g 12-hour format of an hour without leading zeros 1 to 12 |
---|
| 40 | G 24-hour format of an hour without leading zeros 0 to 23 |
---|
| 41 | h 12-hour format of an hour with leading zeros 01 to 12 |
---|
| 42 | H 24-hour format of an hour with leading zeros 00 to 23 |
---|
| 43 | i Minutes, with leading zeros 00 to 59 |
---|
| 44 | s Seconds, with leading zeros 00 to 59 |
---|
| 45 | u Decimal fraction of a second Examples: |
---|
| 46 | (minimum 1 digit, arbitrary number of digits allowed) 001 (i.e. 0.001s) or |
---|
| 47 | 100 (i.e. 0.100s) or |
---|
| 48 | 999 (i.e. 0.999s) or |
---|
| 49 | 999876543210 (i.e. 0.999876543210s) |
---|
| 50 | O Difference to Greenwich time (GMT) in hours and minutes Example: +1030 |
---|
| 51 | P Difference to Greenwich time (GMT) with colon between hours and minutes Example: -08:00 |
---|
| 52 | T Timezone abbreviation of the machine running the code Examples: EST, MDT, PDT ... |
---|
| 53 | Z Timezone offset in seconds (negative if west of UTC, positive if east) -43200 to 50400 |
---|
| 54 | c ISO 8601 date |
---|
| 55 | Notes: Examples: |
---|
| 56 | 1) If unspecified, the month / day defaults to the current month / day, 1991 or |
---|
| 57 | the time defaults to midnight, while the timezone defaults to the 1992-10 or |
---|
| 58 | browser's timezone. If a time is specified, it must include both hours 1993-09-20 or |
---|
| 59 | and minutes. The "T" delimiter, seconds, milliseconds and timezone 1994-08-19T16:20+01:00 or |
---|
| 60 | are optional. 1995-07-18T17:21:28-02:00 or |
---|
| 61 | 2) The decimal fraction of a second, if specified, must contain at 1996-06-17T18:22:29.98765+03:00 or |
---|
| 62 | least 1 digit (there is no limit to the maximum number 1997-05-16T19:23:30,12345-0400 or |
---|
| 63 | of digits allowed), and may be delimited by either a '.' or a ',' 1998-04-15T20:24:31.2468Z or |
---|
| 64 | Refer to the examples on the right for the various levels of 1999-03-14T20:24:32Z or |
---|
| 65 | date-time granularity which are supported, or see 2000-02-13T21:25:33 |
---|
| 66 | http://www.w3.org/TR/NOTE-datetime for more info. 2001-01-12 22:26:34 |
---|
| 67 | U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) 1193432466 or -2138434463 |
---|
| 68 | M$ Microsoft AJAX serialized dates \/Date(1238606590509)\/ (i.e. UTC milliseconds since epoch) or |
---|
| 69 | \/Date(1238606590509+0800)\/ |
---|
| 70 | </pre> |
---|
| 71 | * |
---|
| 72 | * Example usage (note that you must escape format specifiers with '\\' to render them as character literals): |
---|
| 73 | * <pre><code> |
---|
| 74 | // Sample date: |
---|
| 75 | // 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)' |
---|
| 76 | |
---|
| 77 | var dt = new Date('1/10/2007 03:05:01 PM GMT-0600'); |
---|
| 78 | document.write(dt.format('Y-m-d')); // 2007-01-10 |
---|
| 79 | document.write(dt.format('F j, Y, g:i a')); // January 10, 2007, 3:05 pm |
---|
| 80 | document.write(dt.format('l, \\t\\he jS \\of F Y h:i:s A')); // Wednesday, the 10th of January 2007 03:05:01 PM |
---|
| 81 | </code></pre> |
---|
| 82 | * |
---|
| 83 | * Here are some standard date/time patterns that you might find helpful. They |
---|
| 84 | * are not part of the source of Date.js, but to use them you can simply copy this |
---|
| 85 | * block of code into any script that is included after Date.js and they will also become |
---|
| 86 | * globally available on the Date object. Feel free to add or remove patterns as needed in your code. |
---|
| 87 | * <pre><code> |
---|
| 88 | Date.patterns = { |
---|
| 89 | ISO8601Long:"Y-m-d H:i:s", |
---|
| 90 | ISO8601Short:"Y-m-d", |
---|
| 91 | ShortDate: "n/j/Y", |
---|
| 92 | LongDate: "l, F d, Y", |
---|
| 93 | FullDateTime: "l, F d, Y g:i:s A", |
---|
| 94 | MonthDay: "F d", |
---|
| 95 | ShortTime: "g:i A", |
---|
| 96 | LongTime: "g:i:s A", |
---|
| 97 | SortableDateTime: "Y-m-d\\TH:i:s", |
---|
| 98 | UniversalSortableDateTime: "Y-m-d H:i:sO", |
---|
| 99 | YearMonth: "F, Y" |
---|
| 100 | }; |
---|
| 101 | </code></pre> |
---|
| 102 | * |
---|
| 103 | * Example usage: |
---|
| 104 | * <pre><code> |
---|
| 105 | var dt = new Date(); |
---|
| 106 | document.write(dt.format(Date.patterns.ShortDate)); |
---|
| 107 | </code></pre> |
---|
| 108 | * <p>Developer-written, custom formats may be used by supplying both a formatting and a parsing function |
---|
| 109 | * which perform to specialized requirements. The functions are stored in {@link #parseFunctions} and {@link #formatFunctions}.</p> |
---|
| 110 | */ |
---|
| 111 | |
---|
| 112 | /* |
---|
| 113 | * Most of the date-formatting functions below are the excellent work of Baron Schwartz. |
---|
| 114 | * (see http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/) |
---|
| 115 | * They generate precompiled functions from format patterns instead of parsing and |
---|
| 116 | * processing each pattern every time a date is formatted. These functions are available |
---|
| 117 | * on every Date object. |
---|
| 118 | */ |
---|
| 119 | |
---|
| 120 | (function() { |
---|
| 121 | |
---|
| 122 | /** |
---|
| 123 | * Global flag which determines if strict date parsing should be used. |
---|
| 124 | * Strict date parsing will not roll-over invalid dates, which is the |
---|
| 125 | * default behaviour of javascript Date objects. |
---|
| 126 | * (see {@link #parseDate} for more information) |
---|
| 127 | * Defaults to <tt>false</tt>. |
---|
| 128 | * @static |
---|
| 129 | * @type Boolean |
---|
| 130 | */ |
---|
| 131 | Date.useStrict = false; |
---|
| 132 | |
---|
| 133 | |
---|
| 134 | // create private copy of Ext's String.format() method |
---|
| 135 | // - to remove unnecessary dependency |
---|
| 136 | // - to resolve namespace conflict with M$-Ajax's implementation |
---|
| 137 | function xf(format) { |
---|
| 138 | var args = Array.prototype.slice.call(arguments, 1); |
---|
| 139 | return format.replace(/\{(\d+)\}/g, function(m, i) { |
---|
| 140 | return args[i]; |
---|
| 141 | }); |
---|
| 142 | } |
---|
| 143 | |
---|
| 144 | |
---|
| 145 | // private |
---|
| 146 | Date.formatCodeToRegex = function(character, currentGroup) { |
---|
| 147 | // Note: currentGroup - position in regex result array (see notes for Date.parseCodes below) |
---|
| 148 | var p = Date.parseCodes[character]; |
---|
| 149 | |
---|
| 150 | if (p) { |
---|
| 151 | p = typeof p == 'function'? p() : p; |
---|
| 152 | Date.parseCodes[character] = p; // reassign function result to prevent repeated execution |
---|
| 153 | } |
---|
| 154 | |
---|
| 155 | return p ? Ext.applyIf({ |
---|
| 156 | c: p.c ? xf(p.c, currentGroup || "{0}") : p.c |
---|
| 157 | }, p) : { |
---|
| 158 | g:0, |
---|
| 159 | c:null, |
---|
| 160 | s:Ext.escapeRe(character) // treat unrecognised characters as literals |
---|
| 161 | }; |
---|
| 162 | }; |
---|
| 163 | |
---|
| 164 | // private shorthand for Date.formatCodeToRegex since we'll be using it fairly often |
---|
| 165 | var $f = Date.formatCodeToRegex; |
---|
| 166 | |
---|
| 167 | Ext.apply(Date, { |
---|
| 168 | /** |
---|
| 169 | * <p>An object hash in which each property is a date parsing function. The property name is the |
---|
| 170 | * format string which that function parses.</p> |
---|
| 171 | * <p>This object is automatically populated with date parsing functions as |
---|
| 172 | * date formats are requested for Ext standard formatting strings.</p> |
---|
| 173 | * <p>Custom parsing functions may be inserted into this object, keyed by a name which from then on |
---|
| 174 | * may be used as a format string to {@link #parseDate}.<p> |
---|
| 175 | * <p>Example:</p><pre><code> |
---|
| 176 | Date.parseFunctions['x-date-format'] = myDateParser; |
---|
| 177 | </code></pre> |
---|
| 178 | * <p>A parsing function should return a Date object, and is passed the following parameters:<div class="mdetail-params"><ul> |
---|
| 179 | * <li><code>date</code> : String<div class="sub-desc">The date string to parse.</div></li> |
---|
| 180 | * <li><code>strict</code> : Boolean<div class="sub-desc">True to validate date strings while parsing |
---|
| 181 | * (i.e. prevent javascript Date "rollover") (The default must be false). |
---|
| 182 | * Invalid date strings should return null when parsed.</div></li> |
---|
| 183 | * </ul></div></p> |
---|
| 184 | * <p>To enable Dates to also be <i>formatted</i> according to that format, a corresponding |
---|
| 185 | * formatting function must be placed into the {@link #formatFunctions} property. |
---|
| 186 | * @property parseFunctions |
---|
| 187 | * @static |
---|
| 188 | * @type Object |
---|
| 189 | */ |
---|
| 190 | parseFunctions: { |
---|
| 191 | "M$": function(input, strict) { |
---|
| 192 | // note: the timezone offset is ignored since the M$ Ajax server sends |
---|
| 193 | // a UTC milliseconds-since-Unix-epoch value (negative values are allowed) |
---|
| 194 | var re = new RegExp('\\/Date\\(([-+])?(\\d+)(?:[+-]\\d{4})?\\)\\/'); |
---|
| 195 | var r = (input || '').match(re); |
---|
| 196 | return r? new Date(((r[1] || '') + r[2]) * 1) : null; |
---|
| 197 | } |
---|
| 198 | }, |
---|
| 199 | parseRegexes: [], |
---|
| 200 | |
---|
| 201 | /** |
---|
| 202 | * <p>An object hash in which each property is a date formatting function. The property name is the |
---|
| 203 | * format string which corresponds to the produced formatted date string.</p> |
---|
| 204 | * <p>This object is automatically populated with date formatting functions as |
---|
| 205 | * date formats are requested for Ext standard formatting strings.</p> |
---|
| 206 | * <p>Custom formatting functions may be inserted into this object, keyed by a name which from then on |
---|
| 207 | * may be used as a format string to {@link #format}. Example:</p><pre><code> |
---|
| 208 | Date.formatFunctions['x-date-format'] = myDateFormatter; |
---|
| 209 | </code></pre> |
---|
| 210 | * <p>A formatting function should return a string representation of the passed Date object, and is passed the following parameters:<div class="mdetail-params"><ul> |
---|
| 211 | * <li><code>date</code> : Date<div class="sub-desc">The Date to format.</div></li> |
---|
| 212 | * </ul></div></p> |
---|
| 213 | * <p>To enable date strings to also be <i>parsed</i> according to that format, a corresponding |
---|
| 214 | * parsing function must be placed into the {@link #parseFunctions} property. |
---|
| 215 | * @property formatFunctions |
---|
| 216 | * @static |
---|
| 217 | * @type Object |
---|
| 218 | */ |
---|
| 219 | formatFunctions: { |
---|
| 220 | "M$": function() { |
---|
| 221 | // UTC milliseconds since Unix epoch (M$-AJAX serialized date format (MRSF)) |
---|
| 222 | return '\\/Date(' + this.getTime() + ')\\/'; |
---|
| 223 | } |
---|
| 224 | }, |
---|
| 225 | |
---|
| 226 | y2kYear : 50, |
---|
| 227 | |
---|
| 228 | /** |
---|
| 229 | * Date interval constant |
---|
| 230 | * @static |
---|
| 231 | * @type String |
---|
| 232 | */ |
---|
| 233 | MILLI : "ms", |
---|
| 234 | |
---|
| 235 | /** |
---|
| 236 | * Date interval constant |
---|
| 237 | * @static |
---|
| 238 | * @type String |
---|
| 239 | */ |
---|
| 240 | SECOND : "s", |
---|
| 241 | |
---|
| 242 | /** |
---|
| 243 | * Date interval constant |
---|
| 244 | * @static |
---|
| 245 | * @type String |
---|
| 246 | */ |
---|
| 247 | MINUTE : "mi", |
---|
| 248 | |
---|
| 249 | /** Date interval constant |
---|
| 250 | * @static |
---|
| 251 | * @type String |
---|
| 252 | */ |
---|
| 253 | HOUR : "h", |
---|
| 254 | |
---|
| 255 | /** |
---|
| 256 | * Date interval constant |
---|
| 257 | * @static |
---|
| 258 | * @type String |
---|
| 259 | */ |
---|
| 260 | DAY : "d", |
---|
| 261 | |
---|
| 262 | /** |
---|
| 263 | * Date interval constant |
---|
| 264 | * @static |
---|
| 265 | * @type String |
---|
| 266 | */ |
---|
| 267 | MONTH : "mo", |
---|
| 268 | |
---|
| 269 | /** |
---|
| 270 | * Date interval constant |
---|
| 271 | * @static |
---|
| 272 | * @type String |
---|
| 273 | */ |
---|
| 274 | YEAR : "y", |
---|
| 275 | |
---|
| 276 | /** |
---|
| 277 | * <p>An object hash containing default date values used during date parsing.</p> |
---|
| 278 | * <p>The following properties are available:<div class="mdetail-params"><ul> |
---|
| 279 | * <li><code>y</code> : Number<div class="sub-desc">The default year value. (defaults to undefined)</div></li> |
---|
| 280 | * <li><code>m</code> : Number<div class="sub-desc">The default 1-based month value. (defaults to undefined)</div></li> |
---|
| 281 | * <li><code>d</code> : Number<div class="sub-desc">The default day value. (defaults to undefined)</div></li> |
---|
| 282 | * <li><code>h</code> : Number<div class="sub-desc">The default hour value. (defaults to undefined)</div></li> |
---|
| 283 | * <li><code>i</code> : Number<div class="sub-desc">The default minute value. (defaults to undefined)</div></li> |
---|
| 284 | * <li><code>s</code> : Number<div class="sub-desc">The default second value. (defaults to undefined)</div></li> |
---|
| 285 | * <li><code>ms</code> : Number<div class="sub-desc">The default millisecond value. (defaults to undefined)</div></li> |
---|
| 286 | * </ul></div></p> |
---|
| 287 | * <p>Override these properties to customize the default date values used by the {@link #parseDate} method.</p> |
---|
| 288 | * <p><b>Note: In countries which experience Daylight Saving Time (i.e. DST), the <tt>h</tt>, <tt>i</tt>, <tt>s</tt> |
---|
| 289 | * and <tt>ms</tt> properties may coincide with the exact time in which DST takes effect. |
---|
| 290 | * It is the responsiblity of the developer to account for this.</b></p> |
---|
| 291 | * Example Usage: |
---|
| 292 | * <pre><code> |
---|
| 293 | // set default day value to the first day of the month |
---|
| 294 | Date.defaults.d = 1; |
---|
| 295 | |
---|
| 296 | // parse a February date string containing only year and month values. |
---|
| 297 | // setting the default day value to 1 prevents weird date rollover issues |
---|
| 298 | // when attempting to parse the following date string on, for example, March 31st 2009. |
---|
| 299 | Date.parseDate('2009-02', 'Y-m'); // returns a Date object representing February 1st 2009 |
---|
| 300 | </code></pre> |
---|
| 301 | * @property defaults |
---|
| 302 | * @static |
---|
| 303 | * @type Object |
---|
| 304 | */ |
---|
| 305 | defaults: {}, |
---|
| 306 | |
---|
| 307 | /** |
---|
| 308 | * An array of textual day names. |
---|
| 309 | * Override these values for international dates. |
---|
| 310 | * Example: |
---|
| 311 | * <pre><code> |
---|
| 312 | Date.dayNames = [ |
---|
| 313 | 'SundayInYourLang', |
---|
| 314 | 'MondayInYourLang', |
---|
| 315 | ... |
---|
| 316 | ]; |
---|
| 317 | </code></pre> |
---|
| 318 | * @type Array |
---|
| 319 | * @static |
---|
| 320 | */ |
---|
| 321 | dayNames : [ |
---|
| 322 | "Sunday", |
---|
| 323 | "Monday", |
---|
| 324 | "Tuesday", |
---|
| 325 | "Wednesday", |
---|
| 326 | "Thursday", |
---|
| 327 | "Friday", |
---|
| 328 | "Saturday" |
---|
| 329 | ], |
---|
| 330 | |
---|
| 331 | /** |
---|
| 332 | * An array of textual month names. |
---|
| 333 | * Override these values for international dates. |
---|
| 334 | * Example: |
---|
| 335 | * <pre><code> |
---|
| 336 | Date.monthNames = [ |
---|
| 337 | 'JanInYourLang', |
---|
| 338 | 'FebInYourLang', |
---|
| 339 | ... |
---|
| 340 | ]; |
---|
| 341 | </code></pre> |
---|
| 342 | * @type Array |
---|
| 343 | * @static |
---|
| 344 | */ |
---|
| 345 | monthNames : [ |
---|
| 346 | "January", |
---|
| 347 | "February", |
---|
| 348 | "March", |
---|
| 349 | "April", |
---|
| 350 | "May", |
---|
| 351 | "June", |
---|
| 352 | "July", |
---|
| 353 | "August", |
---|
| 354 | "September", |
---|
| 355 | "October", |
---|
| 356 | "November", |
---|
| 357 | "December" |
---|
| 358 | ], |
---|
| 359 | |
---|
| 360 | /** |
---|
| 361 | * An object hash of zero-based javascript month numbers (with short month names as keys. note: keys are case-sensitive). |
---|
| 362 | * Override these values for international dates. |
---|
| 363 | * Example: |
---|
| 364 | * <pre><code> |
---|
| 365 | Date.monthNumbers = { |
---|
| 366 | 'ShortJanNameInYourLang':0, |
---|
| 367 | 'ShortFebNameInYourLang':1, |
---|
| 368 | ... |
---|
| 369 | }; |
---|
| 370 | </code></pre> |
---|
| 371 | * @type Object |
---|
| 372 | * @static |
---|
| 373 | */ |
---|
| 374 | monthNumbers : { |
---|
| 375 | Jan:0, |
---|
| 376 | Feb:1, |
---|
| 377 | Mar:2, |
---|
| 378 | Apr:3, |
---|
| 379 | May:4, |
---|
| 380 | Jun:5, |
---|
| 381 | Jul:6, |
---|
| 382 | Aug:7, |
---|
| 383 | Sep:8, |
---|
| 384 | Oct:9, |
---|
| 385 | Nov:10, |
---|
| 386 | Dec:11 |
---|
| 387 | }, |
---|
| 388 | |
---|
| 389 | /** |
---|
| 390 | * Get the short month name for the given month number. |
---|
| 391 | * Override this function for international dates. |
---|
| 392 | * @param {Number} month A zero-based javascript month number. |
---|
| 393 | * @return {String} The short month name. |
---|
| 394 | * @static |
---|
| 395 | */ |
---|
| 396 | getShortMonthName : function(month) { |
---|
| 397 | return Date.monthNames[month].substring(0, 3); |
---|
| 398 | }, |
---|
| 399 | |
---|
| 400 | /** |
---|
| 401 | * Get the short day name for the given day number. |
---|
| 402 | * Override this function for international dates. |
---|
| 403 | * @param {Number} day A zero-based javascript day number. |
---|
| 404 | * @return {String} The short day name. |
---|
| 405 | * @static |
---|
| 406 | */ |
---|
| 407 | getShortDayName : function(day) { |
---|
| 408 | return Date.dayNames[day].substring(0, 3); |
---|
| 409 | }, |
---|
| 410 | |
---|
| 411 | /** |
---|
| 412 | * Get the zero-based javascript month number for the given short/full month name. |
---|
| 413 | * Override this function for international dates. |
---|
| 414 | * @param {String} name The short/full month name. |
---|
| 415 | * @return {Number} The zero-based javascript month number. |
---|
| 416 | * @static |
---|
| 417 | */ |
---|
| 418 | getMonthNumber : function(name) { |
---|
| 419 | // handle camel casing for english month names (since the keys for the Date.monthNumbers hash are case sensitive) |
---|
| 420 | return Date.monthNumbers[name.substring(0, 1).toUpperCase() + name.substring(1, 3).toLowerCase()]; |
---|
| 421 | }, |
---|
| 422 | |
---|
| 423 | /** |
---|
| 424 | * Checks if the specified format contains hour information |
---|
| 425 | * @param {Object} format The format to check |
---|
| 426 | * @return {Boolean} True if the format contains hour information |
---|
| 427 | * @static |
---|
| 428 | */ |
---|
| 429 | formatContainsHourInfo : (function(){ |
---|
| 430 | var stripEscapeRe = /(\\.)/g, |
---|
| 431 | hourInfoRe = /([gGhHisucUOPZ]|M\$)/; |
---|
| 432 | return function(format){ |
---|
| 433 | return hourInfoRe.test(format.replace(stripEscapeRe, '')); |
---|
| 434 | }; |
---|
| 435 | })(), |
---|
| 436 | |
---|
| 437 | /** |
---|
| 438 | * The base format-code to formatting-function hashmap used by the {@link #format} method. |
---|
| 439 | * Formatting functions are strings (or functions which return strings) which |
---|
| 440 | * will return the appropriate value when evaluated in the context of the Date object |
---|
| 441 | * from which the {@link #format} method is called. |
---|
| 442 | * Add to / override these mappings for custom date formatting. |
---|
| 443 | * Note: Date.format() treats characters as literals if an appropriate mapping cannot be found. |
---|
| 444 | * Example: |
---|
| 445 | * <pre><code> |
---|
| 446 | Date.formatCodes.x = "String.leftPad(this.getDate(), 2, '0')"; |
---|
| 447 | (new Date()).format("X"); // returns the current day of the month |
---|
| 448 | </code></pre> |
---|
| 449 | * @type Object |
---|
| 450 | * @static |
---|
| 451 | */ |
---|
| 452 | formatCodes : { |
---|
| 453 | d: "String.leftPad(this.getDate(), 2, '0')", |
---|
| 454 | D: "Date.getShortDayName(this.getDay())", // get localised short day name |
---|
| 455 | j: "this.getDate()", |
---|
| 456 | l: "Date.dayNames[this.getDay()]", |
---|
| 457 | N: "(this.getDay() ? this.getDay() : 7)", |
---|
| 458 | S: "this.getSuffix()", |
---|
| 459 | w: "this.getDay()", |
---|
| 460 | z: "this.getDayOfYear()", |
---|
| 461 | W: "String.leftPad(this.getWeekOfYear(), 2, '0')", |
---|
| 462 | F: "Date.monthNames[this.getMonth()]", |
---|
| 463 | m: "String.leftPad(this.getMonth() + 1, 2, '0')", |
---|
| 464 | M: "Date.getShortMonthName(this.getMonth())", // get localised short month name |
---|
| 465 | n: "(this.getMonth() + 1)", |
---|
| 466 | t: "this.getDaysInMonth()", |
---|
| 467 | L: "(this.isLeapYear() ? 1 : 0)", |
---|
| 468 | o: "(this.getFullYear() + (this.getWeekOfYear() == 1 && this.getMonth() > 0 ? +1 : (this.getWeekOfYear() >= 52 && this.getMonth() < 11 ? -1 : 0)))", |
---|
| 469 | Y: "String.leftPad(this.getFullYear(), 4, '0')", |
---|
| 470 | y: "('' + this.getFullYear()).substring(2, 4)", |
---|
| 471 | a: "(this.getHours() < 12 ? 'am' : 'pm')", |
---|
| 472 | A: "(this.getHours() < 12 ? 'AM' : 'PM')", |
---|
| 473 | g: "((this.getHours() % 12) ? this.getHours() % 12 : 12)", |
---|
| 474 | G: "this.getHours()", |
---|
| 475 | h: "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0')", |
---|
| 476 | H: "String.leftPad(this.getHours(), 2, '0')", |
---|
| 477 | i: "String.leftPad(this.getMinutes(), 2, '0')", |
---|
| 478 | s: "String.leftPad(this.getSeconds(), 2, '0')", |
---|
| 479 | u: "String.leftPad(this.getMilliseconds(), 3, '0')", |
---|
| 480 | O: "this.getGMTOffset()", |
---|
| 481 | P: "this.getGMTOffset(true)", |
---|
| 482 | T: "this.getTimezone()", |
---|
| 483 | Z: "(this.getTimezoneOffset() * -60)", |
---|
| 484 | |
---|
| 485 | c: function() { // ISO-8601 -- GMT format |
---|
| 486 | for (var c = "Y-m-dTH:i:sP", code = [], i = 0, l = c.length; i < l; ++i) { |
---|
| 487 | var e = c.charAt(i); |
---|
| 488 | code.push(e == "T" ? "'T'" : Date.getFormatCode(e)); // treat T as a character literal |
---|
| 489 | } |
---|
| 490 | return code.join(" + "); |
---|
| 491 | }, |
---|
| 492 | /* |
---|
| 493 | c: function() { // ISO-8601 -- UTC format |
---|
| 494 | return [ |
---|
| 495 | "this.getUTCFullYear()", "'-'", |
---|
| 496 | "String.leftPad(this.getUTCMonth() + 1, 2, '0')", "'-'", |
---|
| 497 | "String.leftPad(this.getUTCDate(), 2, '0')", |
---|
| 498 | "'T'", |
---|
| 499 | "String.leftPad(this.getUTCHours(), 2, '0')", "':'", |
---|
| 500 | "String.leftPad(this.getUTCMinutes(), 2, '0')", "':'", |
---|
| 501 | "String.leftPad(this.getUTCSeconds(), 2, '0')", |
---|
| 502 | "'Z'" |
---|
| 503 | ].join(" + "); |
---|
| 504 | }, |
---|
| 505 | */ |
---|
| 506 | |
---|
| 507 | U: "Math.round(this.getTime() / 1000)" |
---|
| 508 | }, |
---|
| 509 | |
---|
| 510 | /** |
---|
| 511 | * Checks if the passed Date parameters will cause a javascript Date "rollover". |
---|
| 512 | * @param {Number} year 4-digit year |
---|
| 513 | * @param {Number} month 1-based month-of-year |
---|
| 514 | * @param {Number} day Day of month |
---|
| 515 | * @param {Number} hour (optional) Hour |
---|
| 516 | * @param {Number} minute (optional) Minute |
---|
| 517 | * @param {Number} second (optional) Second |
---|
| 518 | * @param {Number} millisecond (optional) Millisecond |
---|
| 519 | * @return {Boolean} true if the passed parameters do not cause a Date "rollover", false otherwise. |
---|
| 520 | * @static |
---|
| 521 | */ |
---|
| 522 | isValid : function(y, m, d, h, i, s, ms) { |
---|
| 523 | // setup defaults |
---|
| 524 | h = h || 0; |
---|
| 525 | i = i || 0; |
---|
| 526 | s = s || 0; |
---|
| 527 | ms = ms || 0; |
---|
| 528 | |
---|
| 529 | // Special handling for year < 100 |
---|
| 530 | var dt = new Date(y < 100 ? 100 : y, m - 1, d, h, i, s, ms).add(Date.YEAR, y < 100 ? y - 100 : 0); |
---|
| 531 | |
---|
| 532 | return y == dt.getFullYear() && |
---|
| 533 | m == dt.getMonth() + 1 && |
---|
| 534 | d == dt.getDate() && |
---|
| 535 | h == dt.getHours() && |
---|
| 536 | i == dt.getMinutes() && |
---|
| 537 | s == dt.getSeconds() && |
---|
| 538 | ms == dt.getMilliseconds(); |
---|
| 539 | }, |
---|
| 540 | |
---|
| 541 | /** |
---|
| 542 | * Parses the passed string using the specified date format. |
---|
| 543 | * Note that this function expects normal calendar dates, meaning that months are 1-based (i.e. 1 = January). |
---|
| 544 | * The {@link #defaults} hash will be used for any date value (i.e. year, month, day, hour, minute, second or millisecond) |
---|
| 545 | * which cannot be found in the passed string. If a corresponding default date value has not been specified in the {@link #defaults} hash, |
---|
| 546 | * the current date's year, month, day or DST-adjusted zero-hour time value will be used instead. |
---|
| 547 | * Keep in mind that the input date string must precisely match the specified format string |
---|
| 548 | * in order for the parse operation to be successful (failed parse operations return a null value). |
---|
| 549 | * <p>Example:</p><pre><code> |
---|
| 550 | //dt = Fri May 25 2007 (current date) |
---|
| 551 | var dt = new Date(); |
---|
| 552 | |
---|
| 553 | //dt = Thu May 25 2006 (today's month/day in 2006) |
---|
| 554 | dt = Date.parseDate("2006", "Y"); |
---|
| 555 | |
---|
| 556 | //dt = Sun Jan 15 2006 (all date parts specified) |
---|
| 557 | dt = Date.parseDate("2006-01-15", "Y-m-d"); |
---|
| 558 | |
---|
| 559 | //dt = Sun Jan 15 2006 15:20:01 |
---|
| 560 | dt = Date.parseDate("2006-01-15 3:20:01 PM", "Y-m-d g:i:s A"); |
---|
| 561 | |
---|
| 562 | // attempt to parse Sun Feb 29 2006 03:20:01 in strict mode |
---|
| 563 | dt = Date.parseDate("2006-02-29 03:20:01", "Y-m-d H:i:s", true); // returns null |
---|
| 564 | </code></pre> |
---|
| 565 | * @param {String} input The raw date string. |
---|
| 566 | * @param {String} format The expected date string format. |
---|
| 567 | * @param {Boolean} strict (optional) True to validate date strings while parsing (i.e. prevents javascript Date "rollover") |
---|
| 568 | (defaults to false). Invalid date strings will return null when parsed. |
---|
| 569 | * @return {Date} The parsed Date. |
---|
| 570 | * @static |
---|
| 571 | */ |
---|
| 572 | parseDate : function(input, format, strict) { |
---|
| 573 | var p = Date.parseFunctions; |
---|
| 574 | if (p[format] == null) { |
---|
| 575 | Date.createParser(format); |
---|
| 576 | } |
---|
| 577 | return p[format](input, Ext.isDefined(strict) ? strict : Date.useStrict); |
---|
| 578 | }, |
---|
| 579 | |
---|
| 580 | // private |
---|
| 581 | getFormatCode : function(character) { |
---|
| 582 | var f = Date.formatCodes[character]; |
---|
| 583 | |
---|
| 584 | if (f) { |
---|
| 585 | f = typeof f == 'function'? f() : f; |
---|
| 586 | Date.formatCodes[character] = f; // reassign function result to prevent repeated execution |
---|
| 587 | } |
---|
| 588 | |
---|
| 589 | // note: unknown characters are treated as literals |
---|
| 590 | return f || ("'" + String.escape(character) + "'"); |
---|
| 591 | }, |
---|
| 592 | |
---|
| 593 | // private |
---|
| 594 | createFormat : function(format) { |
---|
| 595 | var code = [], |
---|
| 596 | special = false, |
---|
| 597 | ch = ''; |
---|
| 598 | |
---|
| 599 | for (var i = 0; i < format.length; ++i) { |
---|
| 600 | ch = format.charAt(i); |
---|
| 601 | if (!special && ch == "\\") { |
---|
| 602 | special = true; |
---|
| 603 | } else if (special) { |
---|
| 604 | special = false; |
---|
| 605 | code.push("'" + String.escape(ch) + "'"); |
---|
| 606 | } else { |
---|
| 607 | code.push(Date.getFormatCode(ch)); |
---|
| 608 | } |
---|
| 609 | } |
---|
| 610 | Date.formatFunctions[format] = new Function("return " + code.join('+')); |
---|
| 611 | }, |
---|
| 612 | |
---|
| 613 | // private |
---|
| 614 | createParser : function() { |
---|
| 615 | var code = [ |
---|
| 616 | "var dt, y, m, d, h, i, s, ms, o, z, zz, u, v,", |
---|
| 617 | "def = Date.defaults,", |
---|
| 618 | "results = String(input).match(Date.parseRegexes[{0}]);", // either null, or an array of matched strings |
---|
| 619 | |
---|
| 620 | "if(results){", |
---|
| 621 | "{1}", |
---|
| 622 | |
---|
| 623 | "if(u != null){", // i.e. unix time is defined |
---|
| 624 | "v = new Date(u * 1000);", // give top priority to UNIX time |
---|
| 625 | "}else{", |
---|
| 626 | // create Date object representing midnight of the current day; |
---|
| 627 | // this will provide us with our date defaults |
---|
| 628 | // (note: clearTime() handles Daylight Saving Time automatically) |
---|
| 629 | "dt = (new Date()).clearTime();", |
---|
| 630 | |
---|
| 631 | // date calculations (note: these calculations create a dependency on Ext.num()) |
---|
| 632 | "y = Ext.num(y, Ext.num(def.y, dt.getFullYear()));", |
---|
| 633 | "m = Ext.num(m, Ext.num(def.m - 1, dt.getMonth()));", |
---|
| 634 | "d = Ext.num(d, Ext.num(def.d, dt.getDate()));", |
---|
| 635 | |
---|
| 636 | // time calculations (note: these calculations create a dependency on Ext.num()) |
---|
| 637 | "h = Ext.num(h, Ext.num(def.h, dt.getHours()));", |
---|
| 638 | "i = Ext.num(i, Ext.num(def.i, dt.getMinutes()));", |
---|
| 639 | "s = Ext.num(s, Ext.num(def.s, dt.getSeconds()));", |
---|
| 640 | "ms = Ext.num(ms, Ext.num(def.ms, dt.getMilliseconds()));", |
---|
| 641 | |
---|
| 642 | "if(z >= 0 && y >= 0){", |
---|
| 643 | // both the year and zero-based day of year are defined and >= 0. |
---|
| 644 | // these 2 values alone provide sufficient info to create a full date object |
---|
| 645 | |
---|
| 646 | // create Date object representing January 1st for the given year |
---|
| 647 | // handle years < 100 appropriately |
---|
| 648 | "v = new Date(y < 100 ? 100 : y, 0, 1, h, i, s, ms).add(Date.YEAR, y < 100 ? y - 100 : 0);", |
---|
| 649 | |
---|
| 650 | // then add day of year, checking for Date "rollover" if necessary |
---|
| 651 | "v = !strict? v : (strict === true && (z <= 364 || (v.isLeapYear() && z <= 365))? v.add(Date.DAY, z) : null);", |
---|
| 652 | "}else if(strict === true && !Date.isValid(y, m + 1, d, h, i, s, ms)){", // check for Date "rollover" |
---|
| 653 | "v = null;", // invalid date, so return null |
---|
| 654 | "}else{", |
---|
| 655 | // plain old Date object |
---|
| 656 | // handle years < 100 properly |
---|
| 657 | "v = new Date(y < 100 ? 100 : y, m, d, h, i, s, ms).add(Date.YEAR, y < 100 ? y - 100 : 0);", |
---|
| 658 | "}", |
---|
| 659 | "}", |
---|
| 660 | "}", |
---|
| 661 | |
---|
| 662 | "if(v){", |
---|
| 663 | // favour UTC offset over GMT offset |
---|
| 664 | "if(zz != null){", |
---|
| 665 | // reset to UTC, then add offset |
---|
| 666 | "v = v.add(Date.SECOND, -v.getTimezoneOffset() * 60 - zz);", |
---|
| 667 | "}else if(o){", |
---|
| 668 | // reset to GMT, then add offset |
---|
| 669 | "v = v.add(Date.MINUTE, -v.getTimezoneOffset() + (sn == '+'? -1 : 1) * (hr * 60 + mn));", |
---|
| 670 | "}", |
---|
| 671 | "}", |
---|
| 672 | |
---|
| 673 | "return v;" |
---|
| 674 | ].join('\n'); |
---|
| 675 | |
---|
| 676 | return function(format) { |
---|
| 677 | var regexNum = Date.parseRegexes.length, |
---|
| 678 | currentGroup = 1, |
---|
| 679 | calc = [], |
---|
| 680 | regex = [], |
---|
| 681 | special = false, |
---|
| 682 | ch = "", |
---|
| 683 | i = 0, |
---|
| 684 | obj, |
---|
| 685 | last; |
---|
| 686 | |
---|
| 687 | for (; i < format.length; ++i) { |
---|
| 688 | ch = format.charAt(i); |
---|
| 689 | if (!special && ch == "\\") { |
---|
| 690 | special = true; |
---|
| 691 | } else if (special) { |
---|
| 692 | special = false; |
---|
| 693 | regex.push(String.escape(ch)); |
---|
| 694 | } else { |
---|
| 695 | obj = $f(ch, currentGroup); |
---|
| 696 | currentGroup += obj.g; |
---|
| 697 | regex.push(obj.s); |
---|
| 698 | if (obj.g && obj.c) { |
---|
| 699 | if (obj.calcLast) { |
---|
| 700 | last = obj.c; |
---|
| 701 | } else { |
---|
| 702 | calc.push(obj.c); |
---|
| 703 | } |
---|
| 704 | } |
---|
| 705 | } |
---|
| 706 | } |
---|
| 707 | |
---|
| 708 | if (last) { |
---|
| 709 | calc.push(last); |
---|
| 710 | } |
---|
| 711 | |
---|
| 712 | Date.parseRegexes[regexNum] = new RegExp("^" + regex.join('') + "$", 'i'); |
---|
| 713 | Date.parseFunctions[format] = new Function("input", "strict", xf(code, regexNum, calc.join(''))); |
---|
| 714 | }; |
---|
| 715 | }(), |
---|
| 716 | |
---|
| 717 | // private |
---|
| 718 | parseCodes : { |
---|
| 719 | /* |
---|
| 720 | * Notes: |
---|
| 721 | * g = {Number} calculation group (0 or 1. only group 1 contributes to date calculations.) |
---|
| 722 | * c = {String} calculation method (required for group 1. null for group 0. {0} = currentGroup - position in regex result array) |
---|
| 723 | * s = {String} regex pattern. all matches are stored in results[], and are accessible by the calculation mapped to 'c' |
---|
| 724 | */ |
---|
| 725 | d: { |
---|
| 726 | g:1, |
---|
| 727 | c:"d = parseInt(results[{0}], 10);\n", |
---|
| 728 | s:"(\\d{2})" // day of month with leading zeroes (01 - 31) |
---|
| 729 | }, |
---|
| 730 | j: { |
---|
| 731 | g:1, |
---|
| 732 | c:"d = parseInt(results[{0}], 10);\n", |
---|
| 733 | s:"(\\d{1,2})" // day of month without leading zeroes (1 - 31) |
---|
| 734 | }, |
---|
| 735 | D: function() { |
---|
| 736 | for (var a = [], i = 0; i < 7; a.push(Date.getShortDayName(i)), ++i); // get localised short day names |
---|
| 737 | return { |
---|
| 738 | g:0, |
---|
| 739 | c:null, |
---|
| 740 | s:"(?:" + a.join("|") +")" |
---|
| 741 | }; |
---|
| 742 | }, |
---|
| 743 | l: function() { |
---|
| 744 | return { |
---|
| 745 | g:0, |
---|
| 746 | c:null, |
---|
| 747 | s:"(?:" + Date.dayNames.join("|") + ")" |
---|
| 748 | }; |
---|
| 749 | }, |
---|
| 750 | N: { |
---|
| 751 | g:0, |
---|
| 752 | c:null, |
---|
| 753 | s:"[1-7]" // ISO-8601 day number (1 (monday) - 7 (sunday)) |
---|
| 754 | }, |
---|
| 755 | S: { |
---|
| 756 | g:0, |
---|
| 757 | c:null, |
---|
| 758 | s:"(?:st|nd|rd|th)" |
---|
| 759 | }, |
---|
| 760 | w: { |
---|
| 761 | g:0, |
---|
| 762 | c:null, |
---|
| 763 | s:"[0-6]" // javascript day number (0 (sunday) - 6 (saturday)) |
---|
| 764 | }, |
---|
| 765 | z: { |
---|
| 766 | g:1, |
---|
| 767 | c:"z = parseInt(results[{0}], 10);\n", |
---|
| 768 | s:"(\\d{1,3})" // day of the year (0 - 364 (365 in leap years)) |
---|
| 769 | }, |
---|
| 770 | W: { |
---|
| 771 | g:0, |
---|
| 772 | c:null, |
---|
| 773 | s:"(?:\\d{2})" // ISO-8601 week number (with leading zero) |
---|
| 774 | }, |
---|
| 775 | F: function() { |
---|
| 776 | return { |
---|
| 777 | g:1, |
---|
| 778 | c:"m = parseInt(Date.getMonthNumber(results[{0}]), 10);\n", // get localised month number |
---|
| 779 | s:"(" + Date.monthNames.join("|") + ")" |
---|
| 780 | }; |
---|
| 781 | }, |
---|
| 782 | M: function() { |
---|
| 783 | for (var a = [], i = 0; i < 12; a.push(Date.getShortMonthName(i)), ++i); // get localised short month names |
---|
| 784 | return Ext.applyIf({ |
---|
| 785 | s:"(" + a.join("|") + ")" |
---|
| 786 | }, $f("F")); |
---|
| 787 | }, |
---|
| 788 | m: { |
---|
| 789 | g:1, |
---|
| 790 | c:"m = parseInt(results[{0}], 10) - 1;\n", |
---|
| 791 | s:"(\\d{2})" // month number with leading zeros (01 - 12) |
---|
| 792 | }, |
---|
| 793 | n: { |
---|
| 794 | g:1, |
---|
| 795 | c:"m = parseInt(results[{0}], 10) - 1;\n", |
---|
| 796 | s:"(\\d{1,2})" // month number without leading zeros (1 - 12) |
---|
| 797 | }, |
---|
| 798 | t: { |
---|
| 799 | g:0, |
---|
| 800 | c:null, |
---|
| 801 | s:"(?:\\d{2})" // no. of days in the month (28 - 31) |
---|
| 802 | }, |
---|
| 803 | L: { |
---|
| 804 | g:0, |
---|
| 805 | c:null, |
---|
| 806 | s:"(?:1|0)" |
---|
| 807 | }, |
---|
| 808 | o: function() { |
---|
| 809 | return $f("Y"); |
---|
| 810 | }, |
---|
| 811 | Y: { |
---|
| 812 | g:1, |
---|
| 813 | c:"y = parseInt(results[{0}], 10);\n", |
---|
| 814 | s:"(\\d{4})" // 4-digit year |
---|
| 815 | }, |
---|
| 816 | y: { |
---|
| 817 | g:1, |
---|
| 818 | c:"var ty = parseInt(results[{0}], 10);\n" |
---|
| 819 | + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n", // 2-digit year |
---|
| 820 | s:"(\\d{1,2})" |
---|
| 821 | }, |
---|
| 822 | /** |
---|
| 823 | * In the am/pm parsing routines, we allow both upper and lower case |
---|
| 824 | * even though it doesn't exactly match the spec. It gives much more flexibility |
---|
| 825 | * in being able to specify case insensitive regexes. |
---|
| 826 | */ |
---|
| 827 | a: function(){ |
---|
| 828 | return $f("A"); |
---|
| 829 | }, |
---|
| 830 | A: { |
---|
| 831 | // We need to calculate the hour before we apply AM/PM when parsing |
---|
| 832 | calcLast: true, |
---|
| 833 | g:1, |
---|
| 834 | c:"if (/(am)/i.test(results[{0}])) {\n" |
---|
| 835 | + "if (!h || h == 12) { h = 0; }\n" |
---|
| 836 | + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}", |
---|
| 837 | s:"(AM|PM|am|pm)" |
---|
| 838 | }, |
---|
| 839 | g: function() { |
---|
| 840 | return $f("G"); |
---|
| 841 | }, |
---|
| 842 | G: { |
---|
| 843 | g:1, |
---|
| 844 | c:"h = parseInt(results[{0}], 10);\n", |
---|
| 845 | s:"(\\d{1,2})" // 24-hr format of an hour without leading zeroes (0 - 23) |
---|
| 846 | }, |
---|
| 847 | h: function() { |
---|
| 848 | return $f("H"); |
---|
| 849 | }, |
---|
| 850 | H: { |
---|
| 851 | g:1, |
---|
| 852 | c:"h = parseInt(results[{0}], 10);\n", |
---|
| 853 | s:"(\\d{2})" // 24-hr format of an hour with leading zeroes (00 - 23) |
---|
| 854 | }, |
---|
| 855 | i: { |
---|
| 856 | g:1, |
---|
| 857 | c:"i = parseInt(results[{0}], 10);\n", |
---|
| 858 | s:"(\\d{2})" // minutes with leading zeros (00 - 59) |
---|
| 859 | }, |
---|
| 860 | s: { |
---|
| 861 | g:1, |
---|
| 862 | c:"s = parseInt(results[{0}], 10);\n", |
---|
| 863 | s:"(\\d{2})" // seconds with leading zeros (00 - 59) |
---|
| 864 | }, |
---|
| 865 | u: { |
---|
| 866 | g:1, |
---|
| 867 | c:"ms = results[{0}]; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n", |
---|
| 868 | s:"(\\d+)" // decimal fraction of a second (minimum = 1 digit, maximum = unlimited) |
---|
| 869 | }, |
---|
| 870 | O: { |
---|
| 871 | g:1, |
---|
| 872 | c:[ |
---|
| 873 | "o = results[{0}];", |
---|
| 874 | "var sn = o.substring(0,1),", // get + / - sign |
---|
| 875 | "hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60),", // get hours (performs minutes-to-hour conversion also, just in case) |
---|
| 876 | "mn = o.substring(3,5) % 60;", // get minutes |
---|
| 877 | "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + String.leftPad(hr, 2, '0') + String.leftPad(mn, 2, '0')) : null;\n" // -12hrs <= GMT offset <= 14hrs |
---|
| 878 | ].join("\n"), |
---|
| 879 | s: "([+\-]\\d{4})" // GMT offset in hrs and mins |
---|
| 880 | }, |
---|
| 881 | P: { |
---|
| 882 | g:1, |
---|
| 883 | c:[ |
---|
| 884 | "o = results[{0}];", |
---|
| 885 | "var sn = o.substring(0,1),", // get + / - sign |
---|
| 886 | "hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60),", // get hours (performs minutes-to-hour conversion also, just in case) |
---|
| 887 | "mn = o.substring(4,6) % 60;", // get minutes |
---|
| 888 | "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + String.leftPad(hr, 2, '0') + String.leftPad(mn, 2, '0')) : null;\n" // -12hrs <= GMT offset <= 14hrs |
---|
| 889 | ].join("\n"), |
---|
| 890 | s: "([+\-]\\d{2}:\\d{2})" // GMT offset in hrs and mins (with colon separator) |
---|
| 891 | }, |
---|
| 892 | T: { |
---|
| 893 | g:0, |
---|
| 894 | c:null, |
---|
| 895 | s:"[A-Z]{1,4}" // timezone abbrev. may be between 1 - 4 chars |
---|
| 896 | }, |
---|
| 897 | Z: { |
---|
| 898 | g:1, |
---|
| 899 | c:"zz = results[{0}] * 1;\n" // -43200 <= UTC offset <= 50400 |
---|
| 900 | + "zz = (-43200 <= zz && zz <= 50400)? zz : null;\n", |
---|
| 901 | s:"([+\-]?\\d{1,5})" // leading '+' sign is optional for UTC offset |
---|
| 902 | }, |
---|
| 903 | c: function() { |
---|
| 904 | var calc = [], |
---|
| 905 | arr = [ |
---|
| 906 | $f("Y", 1), // year |
---|
| 907 | $f("m", 2), // month |
---|
| 908 | $f("d", 3), // day |
---|
| 909 | $f("h", 4), // hour |
---|
| 910 | $f("i", 5), // minute |
---|
| 911 | $f("s", 6), // second |
---|
| 912 | {c:"ms = results[7] || '0'; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n"}, // decimal fraction of a second (minimum = 1 digit, maximum = unlimited) |
---|
| 913 | {c:[ // allow either "Z" (i.e. UTC) or "-0530" or "+08:00" (i.e. UTC offset) timezone delimiters. assumes local timezone if no timezone is specified |
---|
| 914 | "if(results[8]) {", // timezone specified |
---|
| 915 | "if(results[8] == 'Z'){", |
---|
| 916 | "zz = 0;", // UTC |
---|
| 917 | "}else if (results[8].indexOf(':') > -1){", |
---|
| 918 | $f("P", 8).c, // timezone offset with colon separator |
---|
| 919 | "}else{", |
---|
| 920 | $f("O", 8).c, // timezone offset without colon separator |
---|
| 921 | "}", |
---|
| 922 | "}" |
---|
| 923 | ].join('\n')} |
---|
| 924 | ]; |
---|
| 925 | |
---|
| 926 | for (var i = 0, l = arr.length; i < l; ++i) { |
---|
| 927 | calc.push(arr[i].c); |
---|
| 928 | } |
---|
| 929 | |
---|
| 930 | return { |
---|
| 931 | g:1, |
---|
| 932 | c:calc.join(""), |
---|
| 933 | s:[ |
---|
| 934 | arr[0].s, // year (required) |
---|
| 935 | "(?:", "-", arr[1].s, // month (optional) |
---|
| 936 | "(?:", "-", arr[2].s, // day (optional) |
---|
| 937 | "(?:", |
---|
| 938 | "(?:T| )?", // time delimiter -- either a "T" or a single blank space |
---|
| 939 | arr[3].s, ":", arr[4].s, // hour AND minute, delimited by a single colon (optional). MUST be preceded by either a "T" or a single blank space |
---|
| 940 | "(?::", arr[5].s, ")?", // seconds (optional) |
---|
| 941 | "(?:(?:\\.|,)(\\d+))?", // decimal fraction of a second (e.g. ",12345" or ".98765") (optional) |
---|
| 942 | "(Z|(?:[-+]\\d{2}(?::)?\\d{2}))?", // "Z" (UTC) or "-0530" (UTC offset without colon delimiter) or "+08:00" (UTC offset with colon delimiter) (optional) |
---|
| 943 | ")?", |
---|
| 944 | ")?", |
---|
| 945 | ")?" |
---|
| 946 | ].join("") |
---|
| 947 | }; |
---|
| 948 | }, |
---|
| 949 | U: { |
---|
| 950 | g:1, |
---|
| 951 | c:"u = parseInt(results[{0}], 10);\n", |
---|
| 952 | s:"(-?\\d+)" // leading minus sign indicates seconds before UNIX epoch |
---|
| 953 | } |
---|
| 954 | } |
---|
| 955 | }); |
---|
| 956 | |
---|
| 957 | }()); |
---|
| 958 | |
---|
| 959 | Ext.apply(Date.prototype, { |
---|
| 960 | // private |
---|
| 961 | dateFormat : function(format) { |
---|
| 962 | if (Date.formatFunctions[format] == null) { |
---|
| 963 | Date.createFormat(format); |
---|
| 964 | } |
---|
| 965 | return Date.formatFunctions[format].call(this); |
---|
| 966 | }, |
---|
| 967 | |
---|
| 968 | /** |
---|
| 969 | * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T'). |
---|
| 970 | * |
---|
| 971 | * Note: The date string returned by the javascript Date object's toString() method varies |
---|
| 972 | * between browsers (e.g. FF vs IE) and system region settings (e.g. IE in Asia vs IE in America). |
---|
| 973 | * For a given date string e.g. "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)", |
---|
| 974 | * getTimezone() first tries to get the timezone abbreviation from between a pair of parentheses |
---|
| 975 | * (which may or may not be present), failing which it proceeds to get the timezone abbreviation |
---|
| 976 | * from the GMT offset portion of the date string. |
---|
| 977 | * @return {String} The abbreviated timezone name (e.g. 'CST', 'PDT', 'EDT', 'MPST' ...). |
---|
| 978 | */ |
---|
| 979 | getTimezone : function() { |
---|
| 980 | // the following list shows the differences between date strings from different browsers on a WinXP SP2 machine from an Asian locale: |
---|
| 981 | // |
---|
| 982 | // Opera : "Thu, 25 Oct 2007 22:53:45 GMT+0800" -- shortest (weirdest) date string of the lot |
---|
| 983 | // Safari : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone (same as FF) |
---|
| 984 | // FF : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone |
---|
| 985 | // IE : "Thu Oct 25 22:54:35 UTC+0800 2007" -- (Asian system setting) look for 3-4 letter timezone abbrev |
---|
| 986 | // IE : "Thu Oct 25 17:06:37 PDT 2007" -- (American system setting) look for 3-4 letter timezone abbrev |
---|
| 987 | // |
---|
| 988 | // this crazy regex attempts to guess the correct timezone abbreviation despite these differences. |
---|
| 989 | // step 1: (?:\((.*)\) -- find timezone in parentheses |
---|
| 990 | // step 2: ([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?) -- if nothing was found in step 1, find timezone from timezone offset portion of date string |
---|
| 991 | // step 3: remove all non uppercase characters found in step 1 and 2 |
---|
| 992 | return this.toString().replace(/^.* (?:\((.*)\)|([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?)$/, "$1$2").replace(/[^A-Z]/g, ""); |
---|
| 993 | }, |
---|
| 994 | |
---|
| 995 | /** |
---|
| 996 | * Get the offset from GMT of the current date (equivalent to the format specifier 'O'). |
---|
| 997 | * @param {Boolean} colon (optional) true to separate the hours and minutes with a colon (defaults to false). |
---|
| 998 | * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600'). |
---|
| 999 | */ |
---|
| 1000 | getGMTOffset : function(colon) { |
---|
| 1001 | return (this.getTimezoneOffset() > 0 ? "-" : "+") |
---|
| 1002 | + String.leftPad(Math.floor(Math.abs(this.getTimezoneOffset()) / 60), 2, "0") |
---|
| 1003 | + (colon ? ":" : "") |
---|
| 1004 | + String.leftPad(Math.abs(this.getTimezoneOffset() % 60), 2, "0"); |
---|
| 1005 | }, |
---|
| 1006 | |
---|
| 1007 | /** |
---|
| 1008 | * Get the numeric day number of the year, adjusted for leap year. |
---|
| 1009 | * @return {Number} 0 to 364 (365 in leap years). |
---|
| 1010 | */ |
---|
| 1011 | getDayOfYear: function() { |
---|
| 1012 | var num = 0, |
---|
| 1013 | d = this.clone(), |
---|
| 1014 | m = this.getMonth(), |
---|
| 1015 | i; |
---|
| 1016 | |
---|
| 1017 | for (i = 0, d.setDate(1), d.setMonth(0); i < m; d.setMonth(++i)) { |
---|
| 1018 | num += d.getDaysInMonth(); |
---|
| 1019 | } |
---|
| 1020 | return num + this.getDate() - 1; |
---|
| 1021 | }, |
---|
| 1022 | |
---|
| 1023 | /** |
---|
| 1024 | * Get the numeric ISO-8601 week number of the year. |
---|
| 1025 | * (equivalent to the format specifier 'W', but without a leading zero). |
---|
| 1026 | * @return {Number} 1 to 53 |
---|
| 1027 | */ |
---|
| 1028 | getWeekOfYear : function() { |
---|
| 1029 | // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm |
---|
| 1030 | var ms1d = 864e5, // milliseconds in a day |
---|
| 1031 | ms7d = 7 * ms1d; // milliseconds in a week |
---|
| 1032 | |
---|
| 1033 | return function() { // return a closure so constants get calculated only once |
---|
| 1034 | var DC3 = Date.UTC(this.getFullYear(), this.getMonth(), this.getDate() + 3) / ms1d, // an Absolute Day Number |
---|
| 1035 | AWN = Math.floor(DC3 / 7), // an Absolute Week Number |
---|
| 1036 | Wyr = new Date(AWN * ms7d).getUTCFullYear(); |
---|
| 1037 | |
---|
| 1038 | return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1; |
---|
| 1039 | }; |
---|
| 1040 | }(), |
---|
| 1041 | |
---|
| 1042 | /** |
---|
| 1043 | * Checks if the current date falls within a leap year. |
---|
| 1044 | * @return {Boolean} True if the current date falls within a leap year, false otherwise. |
---|
| 1045 | */ |
---|
| 1046 | isLeapYear : function() { |
---|
| 1047 | var year = this.getFullYear(); |
---|
| 1048 | return !!((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year))); |
---|
| 1049 | }, |
---|
| 1050 | |
---|
| 1051 | /** |
---|
| 1052 | * Get the first day of the current month, adjusted for leap year. The returned value |
---|
| 1053 | * is the numeric day index within the week (0-6) which can be used in conjunction with |
---|
| 1054 | * the {@link #monthNames} array to retrieve the textual day name. |
---|
| 1055 | * Example: |
---|
| 1056 | * <pre><code> |
---|
| 1057 | var dt = new Date('1/10/2007'); |
---|
| 1058 | document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday' |
---|
| 1059 | </code></pre> |
---|
| 1060 | * @return {Number} The day number (0-6). |
---|
| 1061 | */ |
---|
| 1062 | getFirstDayOfMonth : function() { |
---|
| 1063 | var day = (this.getDay() - (this.getDate() - 1)) % 7; |
---|
| 1064 | return (day < 0) ? (day + 7) : day; |
---|
| 1065 | }, |
---|
| 1066 | |
---|
| 1067 | /** |
---|
| 1068 | * Get the last day of the current month, adjusted for leap year. The returned value |
---|
| 1069 | * is the numeric day index within the week (0-6) which can be used in conjunction with |
---|
| 1070 | * the {@link #monthNames} array to retrieve the textual day name. |
---|
| 1071 | * Example: |
---|
| 1072 | * <pre><code> |
---|
| 1073 | var dt = new Date('1/10/2007'); |
---|
| 1074 | document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday' |
---|
| 1075 | </code></pre> |
---|
| 1076 | * @return {Number} The day number (0-6). |
---|
| 1077 | */ |
---|
| 1078 | getLastDayOfMonth : function() { |
---|
| 1079 | return this.getLastDateOfMonth().getDay(); |
---|
| 1080 | }, |
---|
| 1081 | |
---|
| 1082 | |
---|
| 1083 | /** |
---|
| 1084 | * Get the date of the first day of the month in which this date resides. |
---|
| 1085 | * @return {Date} |
---|
| 1086 | */ |
---|
| 1087 | getFirstDateOfMonth : function() { |
---|
| 1088 | return new Date(this.getFullYear(), this.getMonth(), 1); |
---|
| 1089 | }, |
---|
| 1090 | |
---|
| 1091 | /** |
---|
| 1092 | * Get the date of the last day of the month in which this date resides. |
---|
| 1093 | * @return {Date} |
---|
| 1094 | */ |
---|
| 1095 | getLastDateOfMonth : function() { |
---|
| 1096 | return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth()); |
---|
| 1097 | }, |
---|
| 1098 | |
---|
| 1099 | /** |
---|
| 1100 | * Get the number of days in the current month, adjusted for leap year. |
---|
| 1101 | * @return {Number} The number of days in the month. |
---|
| 1102 | */ |
---|
| 1103 | getDaysInMonth: function() { |
---|
| 1104 | var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; |
---|
| 1105 | |
---|
| 1106 | return function() { // return a closure for efficiency |
---|
| 1107 | var m = this.getMonth(); |
---|
| 1108 | |
---|
| 1109 | return m == 1 && this.isLeapYear() ? 29 : daysInMonth[m]; |
---|
| 1110 | }; |
---|
| 1111 | }(), |
---|
| 1112 | |
---|
| 1113 | /** |
---|
| 1114 | * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S'). |
---|
| 1115 | * @return {String} 'st, 'nd', 'rd' or 'th'. |
---|
| 1116 | */ |
---|
| 1117 | getSuffix : function() { |
---|
| 1118 | switch (this.getDate()) { |
---|
| 1119 | case 1: |
---|
| 1120 | case 21: |
---|
| 1121 | case 31: |
---|
| 1122 | return "st"; |
---|
| 1123 | case 2: |
---|
| 1124 | case 22: |
---|
| 1125 | return "nd"; |
---|
| 1126 | case 3: |
---|
| 1127 | case 23: |
---|
| 1128 | return "rd"; |
---|
| 1129 | default: |
---|
| 1130 | return "th"; |
---|
| 1131 | } |
---|
| 1132 | }, |
---|
| 1133 | |
---|
| 1134 | /** |
---|
| 1135 | * Creates and returns a new Date instance with the exact same date value as the called instance. |
---|
| 1136 | * Dates are copied and passed by reference, so if a copied date variable is modified later, the original |
---|
| 1137 | * variable will also be changed. When the intention is to create a new variable that will not |
---|
| 1138 | * modify the original instance, you should create a clone. |
---|
| 1139 | * |
---|
| 1140 | * Example of correctly cloning a date: |
---|
| 1141 | * <pre><code> |
---|
| 1142 | //wrong way: |
---|
| 1143 | var orig = new Date('10/1/2006'); |
---|
| 1144 | var copy = orig; |
---|
| 1145 | copy.setDate(5); |
---|
| 1146 | document.write(orig); //returns 'Thu Oct 05 2006'! |
---|
| 1147 | |
---|
| 1148 | //correct way: |
---|
| 1149 | var orig = new Date('10/1/2006'); |
---|
| 1150 | var copy = orig.clone(); |
---|
| 1151 | copy.setDate(5); |
---|
| 1152 | document.write(orig); //returns 'Thu Oct 01 2006' |
---|
| 1153 | </code></pre> |
---|
| 1154 | * @return {Date} The new Date instance. |
---|
| 1155 | */ |
---|
| 1156 | clone : function() { |
---|
| 1157 | return new Date(this.getTime()); |
---|
| 1158 | }, |
---|
| 1159 | |
---|
| 1160 | /** |
---|
| 1161 | * Checks if the current date is affected by Daylight Saving Time (DST). |
---|
| 1162 | * @return {Boolean} True if the current date is affected by DST. |
---|
| 1163 | */ |
---|
| 1164 | isDST : function() { |
---|
| 1165 | // adapted from http://extjs.com/forum/showthread.php?p=247172#post247172 |
---|
| 1166 | // courtesy of @geoffrey.mcgill |
---|
| 1167 | return new Date(this.getFullYear(), 0, 1).getTimezoneOffset() != this.getTimezoneOffset(); |
---|
| 1168 | }, |
---|
| 1169 | |
---|
| 1170 | /** |
---|
| 1171 | * Attempts to clear all time information from this Date by setting the time to midnight of the same day, |
---|
| 1172 | * automatically adjusting for Daylight Saving Time (DST) where applicable. |
---|
| 1173 | * (note: DST timezone information for the browser's host operating system is assumed to be up-to-date) |
---|
| 1174 | * @param {Boolean} clone true to create a clone of this date, clear the time and return it (defaults to false). |
---|
| 1175 | * @return {Date} this or the clone. |
---|
| 1176 | */ |
---|
| 1177 | clearTime : function(clone) { |
---|
| 1178 | if (clone) { |
---|
| 1179 | return this.clone().clearTime(); |
---|
| 1180 | } |
---|
| 1181 | |
---|
| 1182 | // get current date before clearing time |
---|
| 1183 | var d = this.getDate(); |
---|
| 1184 | |
---|
| 1185 | // clear time |
---|
| 1186 | this.setHours(0); |
---|
| 1187 | this.setMinutes(0); |
---|
| 1188 | this.setSeconds(0); |
---|
| 1189 | this.setMilliseconds(0); |
---|
| 1190 | |
---|
| 1191 | if (this.getDate() != d) { // account for DST (i.e. day of month changed when setting hour = 0) |
---|
| 1192 | // note: DST adjustments are assumed to occur in multiples of 1 hour (this is almost always the case) |
---|
| 1193 | // refer to http://www.timeanddate.com/time/aboutdst.html for the (rare) exceptions to this rule |
---|
| 1194 | |
---|
| 1195 | // increment hour until cloned date == current date |
---|
| 1196 | for (var hr = 1, c = this.add(Date.HOUR, hr); c.getDate() != d; hr++, c = this.add(Date.HOUR, hr)); |
---|
| 1197 | |
---|
| 1198 | this.setDate(d); |
---|
| 1199 | this.setHours(c.getHours()); |
---|
| 1200 | } |
---|
| 1201 | |
---|
| 1202 | return this; |
---|
| 1203 | }, |
---|
| 1204 | |
---|
| 1205 | /** |
---|
| 1206 | * Provides a convenient method for performing basic date arithmetic. This method |
---|
| 1207 | * does not modify the Date instance being called - it creates and returns |
---|
| 1208 | * a new Date instance containing the resulting date value. |
---|
| 1209 | * |
---|
| 1210 | * Examples: |
---|
| 1211 | * <pre><code> |
---|
| 1212 | // Basic usage: |
---|
| 1213 | var dt = new Date('10/29/2006').add(Date.DAY, 5); |
---|
| 1214 | document.write(dt); //returns 'Fri Nov 03 2006 00:00:00' |
---|
| 1215 | |
---|
| 1216 | // Negative values will be subtracted: |
---|
| 1217 | var dt2 = new Date('10/1/2006').add(Date.DAY, -5); |
---|
| 1218 | document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00' |
---|
| 1219 | |
---|
| 1220 | // You can even chain several calls together in one line: |
---|
| 1221 | var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30); |
---|
| 1222 | document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00' |
---|
| 1223 | </code></pre> |
---|
| 1224 | * |
---|
| 1225 | * @param {String} interval A valid date interval enum value. |
---|
| 1226 | * @param {Number} value The amount to add to the current date. |
---|
| 1227 | * @return {Date} The new Date instance. |
---|
| 1228 | */ |
---|
| 1229 | add : function(interval, value) { |
---|
| 1230 | var d = this.clone(); |
---|
| 1231 | if (!interval || value === 0) return d; |
---|
| 1232 | |
---|
| 1233 | switch(interval.toLowerCase()) { |
---|
| 1234 | case Date.MILLI: |
---|
| 1235 | d.setMilliseconds(this.getMilliseconds() + value); |
---|
| 1236 | break; |
---|
| 1237 | case Date.SECOND: |
---|
| 1238 | d.setSeconds(this.getSeconds() + value); |
---|
| 1239 | break; |
---|
| 1240 | case Date.MINUTE: |
---|
| 1241 | d.setMinutes(this.getMinutes() + value); |
---|
| 1242 | break; |
---|
| 1243 | case Date.HOUR: |
---|
| 1244 | d.setHours(this.getHours() + value); |
---|
| 1245 | break; |
---|
| 1246 | case Date.DAY: |
---|
| 1247 | d.setDate(this.getDate() + value); |
---|
| 1248 | break; |
---|
| 1249 | case Date.MONTH: |
---|
| 1250 | var day = this.getDate(); |
---|
| 1251 | if (day > 28) { |
---|
| 1252 | day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate()); |
---|
| 1253 | } |
---|
| 1254 | d.setDate(day); |
---|
| 1255 | d.setMonth(this.getMonth() + value); |
---|
| 1256 | break; |
---|
| 1257 | case Date.YEAR: |
---|
| 1258 | d.setFullYear(this.getFullYear() + value); |
---|
| 1259 | break; |
---|
| 1260 | } |
---|
| 1261 | return d; |
---|
| 1262 | }, |
---|
| 1263 | |
---|
| 1264 | /** |
---|
| 1265 | * Checks if this date falls on or between the given start and end dates. |
---|
| 1266 | * @param {Date} start Start date |
---|
| 1267 | * @param {Date} end End date |
---|
| 1268 | * @return {Boolean} true if this date falls on or between the given start and end dates. |
---|
| 1269 | */ |
---|
| 1270 | between : function(start, end) { |
---|
| 1271 | var t = this.getTime(); |
---|
| 1272 | return start.getTime() <= t && t <= end.getTime(); |
---|
| 1273 | } |
---|
| 1274 | }); |
---|
| 1275 | |
---|
| 1276 | |
---|
| 1277 | /** |
---|
| 1278 | * Formats a date given the supplied format string. |
---|
| 1279 | * @param {String} format The format string. |
---|
| 1280 | * @return {String} The formatted date. |
---|
| 1281 | * @method format |
---|
| 1282 | */ |
---|
| 1283 | Date.prototype.format = Date.prototype.dateFormat; |
---|
| 1284 | |
---|
| 1285 | |
---|
| 1286 | // private |
---|
| 1287 | if (Ext.isSafari && (navigator.userAgent.match(/WebKit\/(\d+)/)[1] || NaN) < 420) { |
---|
| 1288 | Ext.apply(Date.prototype, { |
---|
| 1289 | _xMonth : Date.prototype.setMonth, |
---|
| 1290 | _xDate : Date.prototype.setDate, |
---|
| 1291 | |
---|
| 1292 | // Bug in Safari 1.3, 2.0 (WebKit build < 420) |
---|
| 1293 | // Date.setMonth does not work consistently if iMonth is not 0-11 |
---|
| 1294 | setMonth : function(num) { |
---|
| 1295 | if (num <= -1) { |
---|
| 1296 | var n = Math.ceil(-num), |
---|
| 1297 | back_year = Math.ceil(n / 12), |
---|
| 1298 | month = (n % 12) ? 12 - n % 12 : 0; |
---|
| 1299 | |
---|
| 1300 | this.setFullYear(this.getFullYear() - back_year); |
---|
| 1301 | |
---|
| 1302 | return this._xMonth(month); |
---|
| 1303 | } else { |
---|
| 1304 | return this._xMonth(num); |
---|
| 1305 | } |
---|
| 1306 | }, |
---|
| 1307 | |
---|
| 1308 | // Bug in setDate() method (resolved in WebKit build 419.3, so to be safe we target Webkit builds < 420) |
---|
| 1309 | // The parameter for Date.setDate() is converted to a signed byte integer in Safari |
---|
| 1310 | // http://brianary.blogspot.com/2006/03/safari-date-bug.html |
---|
| 1311 | setDate : function(d) { |
---|
| 1312 | // use setTime() to workaround setDate() bug |
---|
| 1313 | // subtract current day of month in milliseconds, then add desired day of month in milliseconds |
---|
| 1314 | return this.setTime(this.getTime() - (this.getDate() - d) * 864e5); |
---|
| 1315 | } |
---|
| 1316 | }); |
---|
| 1317 | } |
---|
| 1318 | |
---|
| 1319 | |
---|
| 1320 | |
---|
| 1321 | /* Some basic Date tests... (requires Firebug) |
---|
| 1322 | |
---|
| 1323 | Date.parseDate('', 'c'); // call Date.parseDate() once to force computation of regex string so we can console.log() it |
---|
| 1324 | console.log('Insane Regex for "c" format: %o', Date.parseCodes.c.s); // view the insane regex for the "c" format specifier |
---|
| 1325 | |
---|
| 1326 | // standard tests |
---|
| 1327 | console.group('Standard Date.parseDate() Tests'); |
---|
| 1328 | console.log('Date.parseDate("2009-01-05T11:38:56", "c") = %o', Date.parseDate("2009-01-05T11:38:56", "c")); // assumes browser's timezone setting |
---|
| 1329 | console.log('Date.parseDate("2009-02-04T12:37:55.001000", "c") = %o', Date.parseDate("2009-02-04T12:37:55.001000", "c")); // assumes browser's timezone setting |
---|
| 1330 | console.log('Date.parseDate("2009-03-03T13:36:54,101000Z", "c") = %o', Date.parseDate("2009-03-03T13:36:54,101000Z", "c")); // UTC |
---|
| 1331 | console.log('Date.parseDate("2009-04-02T14:35:53.901000-0530", "c") = %o', Date.parseDate("2009-04-02T14:35:53.901000-0530", "c")); // GMT-0530 |
---|
| 1332 | console.log('Date.parseDate("2009-05-01T15:34:52,9876000+08:00", "c") = %o', Date.parseDate("2009-05-01T15:34:52,987600+08:00", "c")); // GMT+08:00 |
---|
| 1333 | console.groupEnd(); |
---|
| 1334 | |
---|
| 1335 | // ISO-8601 format as specified in http://www.w3.org/TR/NOTE-datetime |
---|
| 1336 | // -- accepts ALL 6 levels of date-time granularity |
---|
| 1337 | console.group('ISO-8601 Granularity Test (see http://www.w3.org/TR/NOTE-datetime)'); |
---|
| 1338 | console.log('Date.parseDate("1997", "c") = %o', Date.parseDate("1997", "c")); // YYYY (e.g. 1997) |
---|
| 1339 | console.log('Date.parseDate("1997-07", "c") = %o', Date.parseDate("1997-07", "c")); // YYYY-MM (e.g. 1997-07) |
---|
| 1340 | console.log('Date.parseDate("1997-07-16", "c") = %o', Date.parseDate("1997-07-16", "c")); // YYYY-MM-DD (e.g. 1997-07-16) |
---|
| 1341 | console.log('Date.parseDate("1997-07-16T19:20+01:00", "c") = %o', Date.parseDate("1997-07-16T19:20+01:00", "c")); // YYYY-MM-DDThh:mmTZD (e.g. 1997-07-16T19:20+01:00) |
---|
| 1342 | console.log('Date.parseDate("1997-07-16T19:20:30+01:00", "c") = %o', Date.parseDate("1997-07-16T19:20:30+01:00", "c")); // YYYY-MM-DDThh:mm:ssTZD (e.g. 1997-07-16T19:20:30+01:00) |
---|
| 1343 | console.log('Date.parseDate("1997-07-16T19:20:30.45+01:00", "c") = %o', Date.parseDate("1997-07-16T19:20:30.45+01:00", "c")); // YYYY-MM-DDThh:mm:ss.sTZD (e.g. 1997-07-16T19:20:30.45+01:00) |
---|
| 1344 | console.log('Date.parseDate("1997-07-16 19:20:30.45+01:00", "c") = %o', Date.parseDate("1997-07-16 19:20:30.45+01:00", "c")); // YYYY-MM-DD hh:mm:ss.sTZD (e.g. 1997-07-16T19:20:30.45+01:00) |
---|
| 1345 | console.log('Date.parseDate("1997-13-16T19:20:30.45+01:00", "c", true)= %o', Date.parseDate("1997-13-16T19:20:30.45+01:00", "c", true)); // strict date parsing with invalid month value |
---|
| 1346 | console.groupEnd(); |
---|
| 1347 | |
---|
| 1348 | */ |
---|