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 | */ |
---|