Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/jqplot/src/jsdate.js @ 14777

Last change on this file since 14777 was 9062, checked in by fschoepp, 12 years ago

#1888:
Backend changes:

  • Simplified job state detection (only one hive call will be made to detect all states now, instead of one additional call per job)
  • Reorganized classes (moved model classes into Model folder)

Website changes:

  • Website now heavily uses JavaScript to achieve better user experience
  • JavaScript degrades gracefully, except for plots
  • Tables: Added jquery-datatable-plugin to extend tables (pagination + search functionality)
  • OaaS-Website now uses the design of the HL websites (found in WebApplication branch)
  • Added jqplot to render zoomable line plots for HL-Datatables
  • Styling.js: Plots will be generated by using an ajax call; additional jquery-styling occurs within this file.
  • Added jquery-ui-1.9.2 which is capable of handling/rendering tabs, accordions and resizers.
File size: 53.6 KB
Line 
1
2/**
3 * @fileOverview Date parsing and formatting operations without extending the Date built-in object.
4 * @author Chris Leonello
5 * @version #VERSION#
6 * @date #DATE#
7 */
8 
9(function($) {
10
11    /**
12     * @description
13     * <p>Object with extended date parsing and formatting capabilities.
14     * This library borrows many concepts and ideas from the Date Instance
15     * Methods by Ken Snyder along with some parts of Ken's actual code.</p>
16     *
17     * <p>jsDate takes a different approach by not extending the built-in
18     * Date Object, improving date parsing, allowing for multiple formatting
19     * syntaxes and multiple and more easily expandable localization.</p>
20     *
21     * @author Chris Leonello
22     * @date #date#
23     * @version #VERSION#
24     * @copyright (c) 2010 Chris Leonello
25     * jsDate is currently available for use in all personal or commercial projects
26     * under both the MIT and GPL version 2.0 licenses. This means that you can
27     * choose the license that best suits your project and use it accordingly.
28     *
29     * <p>Ken's origianl Date Instance Methods and copyright notice:</p>
30     * <pre>
31     * Ken Snyder (ken d snyder at gmail dot com)
32     * 2008-09-10
33     * version 2.0.2 (http://kendsnyder.com/sandbox/date/)     
34     * Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/)
35     * </pre>
36     *
37     * @class
38     * @name jsDate
39     * @param  {String | Number | Array | Date&nbsp;Object | Options&nbsp;Object} arguments Optional arguments, either a parsable date/time string,
40     * a JavaScript timestamp, an array of numbers of form [year, month, day, hours, minutes, seconds, milliseconds],
41     * a Date object, or an options object of form {syntax: "perl", date:some Date} where all options are optional.
42     */
43     
44    var jsDate = function () {
45   
46        this.syntax = jsDate.config.syntax;
47        this._type = "jsDate";
48        this.utcOffset = new Date().getTimezoneOffset * 60000;
49        this.proxy = new Date();
50        this.options = {};
51        this.locale = jsDate.regional.getLocale();
52        this.formatString = '';
53        this.defaultCentury = jsDate.config.defaultCentury;
54
55        switch ( arguments.length ) {
56            case 0:
57                break;
58            case 1:
59                // other objects either won't have a _type property or,
60                // if they do, it shouldn't be set to "jsDate", so
61                // assume it is an options argument.
62                if (get_type(arguments[0]) == "[object Object]" && arguments[0]._type != "jsDate") {
63                    var opts = this.options = arguments[0];
64                    this.syntax = opts.syntax || this.syntax;
65                    this.defaultCentury = opts.defaultCentury || this.defaultCentury;
66                    this.proxy = jsDate.createDate(opts.date);
67                }
68                else {
69                    this.proxy = jsDate.createDate(arguments[0]);
70                }
71                break;
72            default:
73                var a = [];
74                for ( var i=0; i<arguments.length; i++ ) {
75                    a.push(arguments[i]);
76                }
77                this.proxy = new Date( this.utcOffset );
78                this.proxy.setFullYear.apply( this.proxy, a.slice(0,3) );
79                if ( a.slice(3).length ) {
80                    this.proxy.setHours.apply( this.proxy, a.slice(3) );
81                }
82                break;
83        }
84    };
85   
86    /**
87     * @namespace Configuration options that will be used as defaults for all instances on the page.
88     * @property {String} defaultLocale The default locale to use [en].
89     * @property {String} syntax The default syntax to use [perl].
90     */
91    jsDate.config = {
92        defaultLocale: 'en',
93        syntax: 'perl',
94        defaultCentury: 1900
95    };
96       
97    /**
98     * Add an arbitrary amount to the currently stored date
99     *
100     * @param {Number} number     
101     * @param {String} unit
102     * @returns {jsDate}       
103     */
104     
105    jsDate.prototype.add = function(number, unit) {
106        var factor = multipliers[unit] || multipliers.day;
107        if (typeof factor == 'number') {
108            this.proxy.setTime(this.proxy.getTime() + (factor * number));
109        } else {
110            factor.add(this, number);
111        }
112        return this;
113    };
114       
115    /**
116     * Create a new jqplot.date object with the same date
117     *
118     * @returns {jsDate}
119     */ 
120     
121    jsDate.prototype.clone = function() {
122            return new jsDate(this.proxy.getTime());
123    };
124
125    /**
126     * Find the difference between this jsDate and another date.
127     *
128     * @param {String| Number| Array| jsDate&nbsp;Object| Date&nbsp;Object} dateObj
129     * @param {String} unit
130     * @param {Boolean} allowDecimal
131     * @returns {Number} Number of units difference between dates.
132     */
133     
134    jsDate.prototype.diff = function(dateObj, unit, allowDecimal) {
135        // ensure we have a Date object
136        dateObj = new jsDate(dateObj);
137        if (dateObj === null) {
138            return null;
139        }
140        // get the multiplying factor integer or factor function
141        var factor = multipliers[unit] || multipliers.day;
142        if (typeof factor == 'number') {
143            // multiply
144            var unitDiff = (this.proxy.getTime() - dateObj.proxy.getTime()) / factor;
145        } else {
146            // run function
147            var unitDiff = factor.diff(this.proxy, dateObj.proxy);
148        }
149        // if decimals are not allowed, round toward zero
150        return (allowDecimal ? unitDiff : Math[unitDiff > 0 ? 'floor' : 'ceil'](unitDiff));         
151    };
152   
153    /**
154     * Get the abbreviated name of the current week day
155     *
156     * @returns {String}
157     */   
158     
159    jsDate.prototype.getAbbrDayName = function() {
160        return jsDate.regional[this.locale]["dayNamesShort"][this.proxy.getDay()];
161    };
162   
163    /**
164     * Get the abbreviated name of the current month
165     *
166     * @returns {String}
167     */
168     
169    jsDate.prototype.getAbbrMonthName = function() {
170        return jsDate.regional[this.locale]["monthNamesShort"][this.proxy.getMonth()];
171    };
172   
173    /**
174     * Get UPPER CASE AM or PM for the current time
175     *
176     * @returns {String}
177     */
178     
179    jsDate.prototype.getAMPM = function() {
180        return this.proxy.getHours() >= 12 ? 'PM' : 'AM';
181    };
182   
183    /**
184     * Get lower case am or pm for the current time
185     *
186     * @returns {String}
187     */
188     
189    jsDate.prototype.getAmPm = function() {
190        return this.proxy.getHours() >= 12 ? 'pm' : 'am';
191    };
192   
193    /**
194     * Get the century (19 for 20th Century)
195     *
196     * @returns {Integer} Century (19 for 20th century).
197     */
198    jsDate.prototype.getCentury = function() {
199        return parseInt(this.proxy.getFullYear()/100, 10);
200    };
201   
202    /**
203     * Implements Date functionality
204     */
205    jsDate.prototype.getDate = function() {
206        return this.proxy.getDate();
207    };
208   
209    /**
210     * Implements Date functionality
211     */
212    jsDate.prototype.getDay = function() {
213        return this.proxy.getDay();
214    };
215   
216    /**
217     * Get the Day of week 1 (Monday) thru 7 (Sunday)
218     *
219     * @returns {Integer} Day of week 1 (Monday) thru 7 (Sunday)
220     */
221    jsDate.prototype.getDayOfWeek = function() {
222        var dow = this.proxy.getDay();
223        return dow===0?7:dow;
224    };
225   
226    /**
227     * Get the day of the year
228     *
229     * @returns {Integer} 1 - 366, day of the year
230     */
231    jsDate.prototype.getDayOfYear = function() {
232        var d = this.proxy;
233        var ms = d - new Date('' + d.getFullYear() + '/1/1 GMT');
234        ms += d.getTimezoneOffset()*60000;
235        d = null;
236        return parseInt(ms/60000/60/24, 10)+1;
237    };
238   
239    /**
240     * Get the name of the current week day
241     *
242     * @returns {String}
243     */ 
244     
245    jsDate.prototype.getDayName = function() {
246        return jsDate.regional[this.locale]["dayNames"][this.proxy.getDay()];
247    };
248   
249    /**
250     * Get the week number of the given year, starting with the first Sunday as the first week
251     * @returns {Integer} Week number (13 for the 13th full week of the year).
252     */
253    jsDate.prototype.getFullWeekOfYear = function() {
254        var d = this.proxy;
255        var doy = this.getDayOfYear();
256        var rdow = 6-d.getDay();
257        var woy = parseInt((doy+rdow)/7, 10);
258        return woy;
259    };
260   
261    /**
262     * Implements Date functionality
263     */
264    jsDate.prototype.getFullYear = function() {
265        return this.proxy.getFullYear();
266    };
267   
268    /**
269     * Get the GMT offset in hours and minutes (e.g. +06:30)
270     *
271     * @returns {String}
272     */
273     
274    jsDate.prototype.getGmtOffset = function() {
275        // divide the minutes offset by 60
276        var hours = this.proxy.getTimezoneOffset() / 60;
277        // decide if we are ahead of or behind GMT
278        var prefix = hours < 0 ? '+' : '-';
279        // remove the negative sign if any
280        hours = Math.abs(hours);
281        // add the +/- to the padded number of hours to : to the padded minutes
282        return prefix + addZeros(Math.floor(hours), 2) + ':' + addZeros((hours % 1) * 60, 2);
283    };
284   
285    /**
286     * Implements Date functionality
287     */
288    jsDate.prototype.getHours = function() {
289        return this.proxy.getHours();
290    };
291   
292    /**
293     * Get the current hour on a 12-hour scheme
294     *
295     * @returns {Integer}
296     */
297     
298    jsDate.prototype.getHours12  = function() {
299        var hours = this.proxy.getHours();
300        return hours > 12 ? hours - 12 : (hours == 0 ? 12 : hours);
301    };
302   
303   
304    jsDate.prototype.getIsoWeek = function() {
305        var d = this.proxy;
306        var woy = d.getWeekOfYear();
307        var dow1_1 = (new Date('' + d.getFullYear() + '/1/1')).getDay();
308        // First week is 01 and not 00 as in the case of %U and %W,
309        // so we add 1 to the final result except if day 1 of the year
310        // is a Monday (then %W returns 01).
311        // We also need to subtract 1 if the day 1 of the year is
312        // Friday-Sunday, so the resulting equation becomes:
313        var idow = woy + (dow1_1 > 4 || dow1_1 <= 1 ? 0 : 1);
314        if(idow == 53 && (new Date('' + d.getFullYear() + '/12/31')).getDay() < 4)
315        {
316            idow = 1;
317        }
318        else if(idow === 0)
319        {
320            d = new jsDate(new Date('' + (d.getFullYear()-1) + '/12/31'));
321            idow = d.getIsoWeek();
322        }
323        d = null;
324        return idow;
325    };
326   
327    /**
328     * Implements Date functionality
329     */
330    jsDate.prototype.getMilliseconds = function() {
331        return this.proxy.getMilliseconds();
332    };
333   
334    /**
335     * Implements Date functionality
336     */
337    jsDate.prototype.getMinutes = function() {
338        return this.proxy.getMinutes();
339    };
340   
341    /**
342     * Implements Date functionality
343     */
344    jsDate.prototype.getMonth = function() {
345        return this.proxy.getMonth();
346    };
347   
348    /**
349     * Get the name of the current month
350     *
351     * @returns {String}
352     */
353     
354    jsDate.prototype.getMonthName = function() {
355        return jsDate.regional[this.locale]["monthNames"][this.proxy.getMonth()];
356    };
357   
358    /**
359     * Get the number of the current month, 1-12
360     *
361     * @returns {Integer}
362     */
363     
364    jsDate.prototype.getMonthNumber = function() {
365        return this.proxy.getMonth() + 1;
366    };
367   
368    /**
369     * Implements Date functionality
370     */
371    jsDate.prototype.getSeconds = function() {
372        return this.proxy.getSeconds();
373    };
374   
375    /**
376     * Return a proper two-digit year integer
377     *
378     * @returns {Integer}
379     */
380     
381    jsDate.prototype.getShortYear = function() {
382        return this.proxy.getYear() % 100;
383    };
384   
385    /**
386     * Implements Date functionality
387     */
388    jsDate.prototype.getTime = function() {
389        return this.proxy.getTime();
390    };
391   
392    /**
393     * Get the timezone abbreviation
394     *
395     * @returns {String} Abbreviation for the timezone
396     */
397    jsDate.prototype.getTimezoneAbbr = function() {
398        return this.proxy.toString().replace(/^.*\(([^)]+)\)$/, '$1');
399    };
400   
401    /**
402     * Get the browser-reported name for the current timezone (e.g. MDT, Mountain Daylight Time)
403     *
404     * @returns {String}
405     */
406    jsDate.prototype.getTimezoneName = function() {
407        var match = /(?:\((.+)\)$| ([A-Z]{3}) )/.exec(this.toString());
408        return match[1] || match[2] || 'GMT' + this.getGmtOffset();
409    };
410   
411    /**
412     * Implements Date functionality
413     */
414    jsDate.prototype.getTimezoneOffset = function() {
415        return this.proxy.getTimezoneOffset();
416    };
417   
418   
419    /**
420     * Get the week number of the given year, starting with the first Monday as the first week
421     * @returns {Integer} Week number (13 for the 13th week of the year).
422     */
423    jsDate.prototype.getWeekOfYear = function() {
424        var doy = this.getDayOfYear();
425        var rdow = 7 - this.getDayOfWeek();
426        var woy = parseInt((doy+rdow)/7, 10);
427        return woy;
428    };
429   
430    /**
431     * Get the current date as a Unix timestamp
432     *
433     * @returns {Integer}
434     */
435     
436    jsDate.prototype.getUnix = function() {
437        return Math.round(this.proxy.getTime() / 1000, 0);
438    };
439   
440    /**
441     * Implements Date functionality
442     */
443    jsDate.prototype.getYear = function() {
444        return this.proxy.getYear();
445    };
446   
447    /**
448     * Return a date one day ahead (or any other unit)
449     *
450     * @param {String} unit Optional, year | month | day | week | hour | minute | second | millisecond
451     * @returns {jsDate}
452     */
453     
454    jsDate.prototype.next = function(unit) {
455        unit = unit || 'day';
456        return this.clone().add(1, unit);
457    };
458   
459    /**
460     * Set the jsDate instance to a new date.
461     *
462     * @param  {String | Number | Array | Date Object | jsDate Object | Options Object} arguments Optional arguments,
463     * either a parsable date/time string,
464     * a JavaScript timestamp, an array of numbers of form [year, month, day, hours, minutes, seconds, milliseconds],
465     * a Date object, jsDate Object or an options object of form {syntax: "perl", date:some Date} where all options are optional.
466     */
467    jsDate.prototype.set = function() {
468        switch ( arguments.length ) {
469            case 0:
470                this.proxy = new Date();
471                break;
472            case 1:
473                // other objects either won't have a _type property or,
474                // if they do, it shouldn't be set to "jsDate", so
475                // assume it is an options argument.
476                if (get_type(arguments[0]) == "[object Object]" && arguments[0]._type != "jsDate") {
477                    var opts = this.options = arguments[0];
478                    this.syntax = opts.syntax || this.syntax;
479                    this.defaultCentury = opts.defaultCentury || this.defaultCentury;
480                    this.proxy = jsDate.createDate(opts.date);
481                }
482                else {
483                    this.proxy = jsDate.createDate(arguments[0]);
484                }
485                break;
486            default:
487                var a = [];
488                for ( var i=0; i<arguments.length; i++ ) {
489                    a.push(arguments[i]);
490                }
491                this.proxy = new Date( this.utcOffset );
492                this.proxy.setFullYear.apply( this.proxy, a.slice(0,3) );
493                if ( a.slice(3).length ) {
494                    this.proxy.setHours.apply( this.proxy, a.slice(3) );
495                }
496                break;
497        }
498    };
499   
500    /**
501     * Sets the day of the month for a specified date according to local time.
502     * @param {Integer} dayValue An integer from 1 to 31, representing the day of the month.
503     */
504    jsDate.prototype.setDate = function(n) {
505        return this.proxy.setDate(n);
506    };
507   
508    /**
509     * Sets the full year for a specified date according to local time.
510     * @param {Integer} yearValue The numeric value of the year, for example, 1995. 
511     * @param {Integer} monthValue Optional, between 0 and 11 representing the months January through December. 
512     * @param {Integer} dayValue Optional, between 1 and 31 representing the day of the month. If you specify the dayValue parameter, you must also specify the monthValue.
513     */
514    jsDate.prototype.setFullYear = function() {
515        return this.proxy.setFullYear.apply(this.proxy, arguments);
516    };
517   
518    /**
519     * Sets the hours for a specified date according to local time.
520     *
521     * @param {Integer} hoursValue An integer between 0 and 23, representing the hour. 
522     * @param {Integer} minutesValue Optional, An integer between 0 and 59, representing the minutes. 
523     * @param {Integer} secondsValue Optional, An integer between 0 and 59, representing the seconds.
524     * If you specify the secondsValue parameter, you must also specify the minutesValue. 
525     * @param {Integer} msValue Optional, A number between 0 and 999, representing the milliseconds.
526     * If you specify the msValue parameter, you must also specify the minutesValue and secondsValue.
527     */
528    jsDate.prototype.setHours = function() {
529        return this.proxy.setHours.apply(this.proxy, arguments);
530    };
531   
532    /**
533     * Implements Date functionality
534     */
535    jsDate.prototype.setMilliseconds = function(n) {
536        return this.proxy.setMilliseconds(n);
537    };
538   
539    /**
540     * Implements Date functionality
541     */
542    jsDate.prototype.setMinutes = function() {
543        return this.proxy.setMinutes.apply(this.proxy, arguments);
544    };
545   
546    /**
547     * Implements Date functionality
548     */
549    jsDate.prototype.setMonth = function() {
550        return this.proxy.setMonth.apply(this.proxy, arguments);
551    };
552   
553    /**
554     * Implements Date functionality
555     */
556    jsDate.prototype.setSeconds = function() {
557        return this.proxy.setSeconds.apply(this.proxy, arguments);
558    };
559   
560    /**
561     * Implements Date functionality
562     */
563    jsDate.prototype.setTime = function(n) {
564        return this.proxy.setTime(n);
565    };
566   
567    /**
568     * Implements Date functionality
569     */
570    jsDate.prototype.setYear = function() {
571        return this.proxy.setYear.apply(this.proxy, arguments);
572    };
573   
574    /**
575     * Provide a formatted string representation of this date.
576     *
577     * @param {String} formatString A format string. 
578     * See: {@link jsDate.formats}.
579     * @returns {String} Date String.
580     */
581           
582    jsDate.prototype.strftime = function(formatString) {
583        formatString = formatString || this.formatString || jsDate.regional[this.locale]['formatString'];
584        return jsDate.strftime(this, formatString, this.syntax);
585    };
586       
587    /**
588     * Return a String representation of this jsDate object.
589     * @returns {String} Date string.
590     */
591   
592    jsDate.prototype.toString = function() {
593        return this.proxy.toString();
594    };
595       
596    /**
597     * Convert the current date to an 8-digit integer (%Y%m%d)
598     *
599     * @returns {Integer}
600     */
601     
602    jsDate.prototype.toYmdInt = function() {
603        return (this.proxy.getFullYear() * 10000) + (this.getMonthNumber() * 100) + this.proxy.getDate();
604    };
605   
606    /**
607     * @namespace Holds localizations for month/day names.
608     * <p>jsDate attempts to detect locale when loaded and defaults to 'en'.
609     * If a localization is detected which is not available, jsDate defaults to 'en'.
610     * Additional localizations can be added after jsDate loads.  After adding a localization,
611     * call the jsDate.regional.getLocale() method.  Currently, en, fr and de are defined.</p>
612     *
613     * <p>Localizations must be an object and have the following properties defined:  monthNames, monthNamesShort, dayNames, dayNamesShort and Localizations are added like:</p>
614     * <pre class="code">
615     * jsDate.regional['en'] = {
616     * monthNames      : 'January February March April May June July August September October November December'.split(' '),
617     * monthNamesShort : 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' '),
618     * dayNames        : 'Sunday Monday Tuesday Wednesday Thursday Friday Saturday'.split(' '),
619     * dayNamesShort   : 'Sun Mon Tue Wed Thu Fri Sat'.split(' ')
620     * };
621     * </pre>
622     * <p>After adding localizations, call <code>jsDate.regional.getLocale();</code> to update the locale setting with the
623     * new localizations.</p>
624     */
625     
626    jsDate.regional = {
627        'en': {
628            monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],
629            monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun','Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
630            dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
631            dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
632            formatString: '%Y-%m-%d %H:%M:%S'
633        },
634       
635        'fr': {
636            monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre'],
637            monthNamesShort: ['Jan','Fév','Mar','Avr','Mai','Jun','Jul','Aoû','Sep','Oct','Nov','Déc'],
638            dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'],
639            dayNamesShort: ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'],
640            formatString: '%Y-%m-%d %H:%M:%S'
641        },
642       
643        'de': {
644            monthNames: ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'],
645            monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'],
646            dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],
647            dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],
648            formatString: '%Y-%m-%d %H:%M:%S'
649        },
650       
651        'es': {
652            monthNames: ['Enero','Febrero','Marzo','Abril','Mayo','Junio', 'Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'],
653            monthNamesShort: ['Ene','Feb','Mar','Abr','May','Jun', 'Jul','Ago','Sep','Oct','Nov','Dic'],
654            dayNames: ['Domingo','Lunes','Martes','Mi&eacute;rcoles','Jueves','Viernes','S&aacute;bado'],
655            dayNamesShort: ['Dom','Lun','Mar','Mi&eacute;','Juv','Vie','S&aacute;b'],
656            formatString: '%Y-%m-%d %H:%M:%S'
657        },
658       
659        'ru': {
660            monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'],
661            monthNamesShort: ['Янв','Фев','Мар','Апр','Май','Июн','Июл','Авг','Сен','Окт','Ноя','Дек'],
662            dayNames: ['воскресенье','понедельник','вторник','среда','четверг','пятница','суббота'],
663            dayNamesShort: ['вск','пнд','втр','срд','чтв','птн','сбт'],
664            formatString: '%Y-%m-%d %H:%M:%S'
665        },
666       
667        'ar': {
668            monthNames: ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'آذار', 'حزيران','تموز', 'آب', 'أيلول',   'تشرين الأول', 'تشرين الثاني', 'كانون الأول'],
669            monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'],
670            dayNames: ['السبت', 'الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة'],
671            dayNamesShort: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'],
672            formatString: '%Y-%m-%d %H:%M:%S'
673        },
674       
675        'pt': {
676            monthNames: ['Janeiro','Fevereiro','Mar&ccedil;o','Abril','Maio','Junho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'],
677            monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun','Jul','Ago','Set','Out','Nov','Dez'],
678            dayNames: ['Domingo','Segunda-feira','Ter&ccedil;a-feira','Quarta-feira','Quinta-feira','Sexta-feira','S&aacute;bado'],
679            dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','S&aacute;b'],
680            formatString: '%Y-%m-%d %H:%M:%S'   
681        },
682       
683        'pt-BR': {
684            monthNames: ['Janeiro','Fevereiro','Mar&ccedil;o','Abril','Maio','Junho', 'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'],
685            monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun','Jul','Ago','Set','Out','Nov','Dez'],
686            dayNames: ['Domingo','Segunda-feira','Ter&ccedil;a-feira','Quarta-feira','Quinta-feira','Sexta-feira','S&aacute;bado'],
687            dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','S&aacute;b'],
688            formatString: '%Y-%m-%d %H:%M:%S'
689        }
690       
691   
692    };
693   
694    // Set english variants to 'en'
695    jsDate.regional['en-US'] = jsDate.regional['en-GB'] = jsDate.regional['en'];
696   
697    /**
698     * Try to determine the users locale based on the lang attribute of the html page.  Defaults to 'en'
699     * if it cannot figure out a locale of if the locale does not have a localization defined.
700     * @returns {String} locale
701     */
702     
703    jsDate.regional.getLocale = function () {
704        var l = jsDate.config.defaultLocale;
705       
706        if ( document && document.getElementsByTagName('html') && document.getElementsByTagName('html')[0].lang ) {
707            l = document.getElementsByTagName('html')[0].lang;
708            if (!jsDate.regional.hasOwnProperty(l)) {
709                l = jsDate.config.defaultLocale;
710            }
711        }
712       
713        return l;
714    };
715   
716    // ms in day
717    var day = 24 * 60 * 60 * 1000;
718   
719    // padd a number with zeros
720    var addZeros = function(num, digits) {
721        num = String(num);
722        var i = digits - num.length;
723        var s = String(Math.pow(10, i)).slice(1);
724        return s.concat(num);
725    };
726
727    // representations used for calculating differences between dates.
728    // This borrows heavily from Ken Snyder's work.
729    var multipliers = {
730        millisecond: 1,
731        second: 1000,
732        minute: 60 * 1000,
733        hour: 60 * 60 * 1000,
734        day: day,
735        week: 7 * day,
736        month: {
737            // add a number of months
738            add: function(d, number) {
739                // add any years needed (increments of 12)
740                multipliers.year.add(d, Math[number > 0 ? 'floor' : 'ceil'](number / 12));
741                // ensure that we properly wrap betwen December and January
742                var prevMonth = d.getMonth() + (number % 12);
743                if (prevMonth == 12) {
744                    prevMonth = 0;
745                    d.setYear(d.getFullYear() + 1);
746                } else if (prevMonth == -1) {
747                    prevMonth = 11;
748                    d.setYear(d.getFullYear() - 1);
749                }
750                d.setMonth(prevMonth);
751            },
752            // get the number of months between two Date objects (decimal to the nearest day)
753            diff: function(d1, d2) {
754                // get the number of years
755                var diffYears = d1.getFullYear() - d2.getFullYear();
756                // get the number of remaining months
757                var diffMonths = d1.getMonth() - d2.getMonth() + (diffYears * 12);
758                // get the number of remaining days
759                var diffDays = d1.getDate() - d2.getDate();
760                // return the month difference with the days difference as a decimal
761                return diffMonths + (diffDays / 30);
762            }
763        },
764        year: {
765            // add a number of years
766            add: function(d, number) {
767                d.setYear(d.getFullYear() + Math[number > 0 ? 'floor' : 'ceil'](number));
768            },
769            // get the number of years between two Date objects (decimal to the nearest day)
770            diff: function(d1, d2) {
771                return multipliers.month.diff(d1, d2) / 12;
772            }
773        }       
774    };
775    //
776    // Alias each multiplier with an 's' to allow 'year' and 'years' for example.
777    // This comes from Ken Snyders work.
778    //
779    for (var unit in multipliers) {
780        if (unit.substring(unit.length - 1) != 's') { // IE will iterate newly added properties :|
781            multipliers[unit + 's'] = multipliers[unit];
782        }
783    }
784   
785    //
786    // take a jsDate instance and a format code and return the formatted value.
787    // This is a somewhat modified version of Ken Snyder's method.
788    //
789    var format = function(d, code, syntax) {
790        // if shorcut codes are used, recursively expand those.
791        if (jsDate.formats[syntax]["shortcuts"][code]) {
792            return jsDate.strftime(d, jsDate.formats[syntax]["shortcuts"][code], syntax);
793        } else {
794            // get the format code function and addZeros() argument
795            var getter = (jsDate.formats[syntax]["codes"][code] || '').split('.');
796            var nbr = d['get' + getter[0]] ? d['get' + getter[0]]() : '';
797            if (getter[1]) {
798                nbr = addZeros(nbr, getter[1]);
799            }
800            return nbr;
801        }       
802    };
803   
804    /**
805     * @static
806     * Static function for convert a date to a string according to a given format.  Also acts as namespace for strftime format codes.
807     * <p>strftime formatting can be accomplished without creating a jsDate object by calling jsDate.strftime():</p>
808     * <pre class="code">
809     * var formattedDate = jsDate.strftime('Feb 8, 2006 8:48:32', '%Y-%m-%d %H:%M:%S');
810     * </pre>
811     * @param {String | Number | Array | jsDate&nbsp;Object | Date&nbsp;Object} date A parsable date string, JavaScript time stamp, Array of form [year, month, day, hours, minutes, seconds, milliseconds], jsDate Object or Date object.
812     * @param {String} formatString String with embedded date formatting codes. 
813     * See: {@link jsDate.formats}.
814     * @param {String} syntax Optional syntax to use [default perl].
815     * @param {String} locale Optional locale to use.
816     * @returns {String} Formatted representation of the date.
817    */
818    //
819    // Logic as implemented here is very similar to Ken Snyder's Date Instance Methods.
820    //
821    jsDate.strftime = function(d, formatString, syntax, locale) {
822        var syn = 'perl';
823        var loc = jsDate.regional.getLocale();
824       
825        // check if syntax and locale are available or reversed
826        if (syntax && jsDate.formats.hasOwnProperty(syntax)) {
827            syn = syntax;
828        }
829        else if (syntax && jsDate.regional.hasOwnProperty(syntax)) {
830            loc = syntax;
831        }
832       
833        if (locale && jsDate.formats.hasOwnProperty(locale)) {
834            syn = locale;
835        }
836        else if (locale && jsDate.regional.hasOwnProperty(locale)) {
837            loc = locale;
838        }
839       
840        if (get_type(d) != "[object Object]" || d._type != "jsDate") {
841            d = new jsDate(d);
842            d.locale = loc;
843        }
844        if (!formatString) {
845            formatString = d.formatString || jsDate.regional[loc]['formatString'];
846        }
847        // default the format string to year-month-day
848        var source = formatString || '%Y-%m-%d',
849            result = '',
850            match;
851        // replace each format code
852        while (source.length > 0) {
853            if (match = source.match(jsDate.formats[syn].codes.matcher)) {
854                result += source.slice(0, match.index);
855                result += (match[1] || '') + format(d, match[2], syn);
856                source = source.slice(match.index + match[0].length);
857            } else {
858                result += source;
859                source = '';
860            }
861        }
862        return result;
863    };
864   
865    /**
866     * @namespace
867     * Namespace to hold format codes and format shortcuts.  "perl" and "php" format codes
868     * and shortcuts are defined by default.  Additional codes and shortcuts can be
869     * added like:
870     *
871     * <pre class="code">
872     * jsDate.formats["perl"] = {
873     *     "codes": {
874     *         matcher: /someregex/,
875     *         Y: "fullYear",  // name of "get" method without the "get",
876     *         ...,            // more codes
877     *     },
878     *     "shortcuts": {
879     *         F: '%Y-%m-%d',
880     *         ...,            // more shortcuts
881     *     }
882     * };
883     * </pre>
884     *
885     * <p>Additionally, ISO and SQL shortcuts are defined and can be accesses via:
886     * <code>jsDate.formats.ISO</code> and <code>jsDate.formats.SQL</code>
887     */
888   
889    jsDate.formats = {
890        ISO:'%Y-%m-%dT%H:%M:%S.%N%G',
891        SQL:'%Y-%m-%d %H:%M:%S'
892    };
893   
894    /**
895     * Perl format codes and shortcuts for strftime.
896     *
897     * A hash (object) of codes where each code must be an array where the first member is
898     * the name of a Date.prototype or jsDate.prototype function to call
899     * and optionally a second member indicating the number to pass to addZeros()
900     *
901     * <p>The following format codes are defined:</p>
902     *
903     * <pre class="code">
904     * Code    Result                    Description
905     * == Years ==           
906     * %Y      2008                      Four-digit year
907     * %y      08                        Two-digit year
908     *
909     * == Months ==         
910     * %m      09                        Two-digit month
911     * %#m     9                         One or two-digit month
912     * %B      September                 Full month name
913     * %b      Sep                       Abbreviated month name
914     *
915     * == Days ==           
916     * %d      05                        Two-digit day of month
917     * %#d     5                         One or two-digit day of month
918     * %e      5                         One or two-digit day of month
919     * %A      Sunday                    Full name of the day of the week
920     * %a      Sun                       Abbreviated name of the day of the week
921     * %w      0                         Number of the day of the week (0 = Sunday, 6 = Saturday)
922     *
923     * == Hours ==           
924     * %H      23                        Hours in 24-hour format (two digits)
925     * %#H     3                         Hours in 24-hour integer format (one or two digits)
926     * %I      11                        Hours in 12-hour format (two digits)
927     * %#I     3                         Hours in 12-hour integer format (one or two digits)
928     * %p      PM                        AM or PM
929     *
930     * == Minutes ==         
931     * %M      09                        Minutes (two digits)
932     * %#M     9                         Minutes (one or two digits)
933     *
934     * == Seconds ==         
935     * %S      02                        Seconds (two digits)
936     * %#S     2                         Seconds (one or two digits)
937     * %s      1206567625723             Unix timestamp (Seconds past 1970-01-01 00:00:00)
938     *
939     * == Milliseconds ==   
940     * %N      008                       Milliseconds (three digits)
941     * %#N     8                         Milliseconds (one to three digits)
942     *
943     * == Timezone ==       
944     * %O      360                       difference in minutes between local time and GMT
945     * %Z      Mountain Standard Time    Name of timezone as reported by browser
946     * %G      06:00                     Hours and minutes between GMT
947     *
948     * == Shortcuts ==       
949     * %F      2008-03-26                %Y-%m-%d
950     * %T      05:06:30                  %H:%M:%S
951     * %X      05:06:30                  %H:%M:%S
952     * %x      03/26/08                  %m/%d/%y
953     * %D      03/26/08                  %m/%d/%y
954     * %#c     Wed Mar 26 15:31:00 2008  %a %b %e %H:%M:%S %Y
955     * %v      3-Sep-2008                %e-%b-%Y
956     * %R      15:31                     %H:%M
957     * %r      03:31:00 PM               %I:%M:%S %p
958     *
959     * == Characters ==     
960     * %n      \n                        Newline
961     * %t      \t                        Tab
962     * %%      %                         Percent Symbol
963     * </pre>
964     *
965     * <p>Formatting shortcuts that will be translated into their longer version.
966     * Be sure that format shortcuts do not refer to themselves: this will cause an infinite loop.</p>
967     *
968     * <p>Format codes and format shortcuts can be redefined after the jsDate
969     * module is imported.</p>
970     *
971     * <p>Note that if you redefine the whole hash (object), you must supply a "matcher"
972     * regex for the parser.  The default matcher is:</p>
973     *
974     * <code>/()%(#?(%|[a-z]))/i</code>
975     *
976     * <p>which corresponds to the Perl syntax used by default.</p>
977     *
978     * <p>By customizing the matcher and format codes, nearly any strftime functionality is possible.</p>
979     */
980     
981    jsDate.formats.perl = {
982        codes: {
983            //
984            // 2-part regex matcher for format codes
985            //
986            // first match must be the character before the code (to account for escaping)
987            // second match must be the format code character(s)
988            //
989            matcher: /()%(#?(%|[a-z]))/i,
990            // year
991            Y: 'FullYear',
992            y: 'ShortYear.2',
993            // month
994            m: 'MonthNumber.2',
995            '#m': 'MonthNumber',
996            B: 'MonthName',
997            b: 'AbbrMonthName',
998            // day
999            d: 'Date.2',
1000            '#d': 'Date',
1001            e: 'Date',
1002            A: 'DayName',
1003            a: 'AbbrDayName',
1004            w: 'Day',
1005            // hours
1006            H: 'Hours.2',
1007            '#H': 'Hours',
1008            I: 'Hours12.2',
1009            '#I': 'Hours12',
1010            p: 'AMPM',
1011            // minutes
1012            M: 'Minutes.2',
1013            '#M': 'Minutes',
1014            // seconds
1015            S: 'Seconds.2',
1016            '#S': 'Seconds',
1017            s: 'Unix',
1018            // milliseconds
1019            N: 'Milliseconds.3',
1020            '#N': 'Milliseconds',
1021            // timezone
1022            O: 'TimezoneOffset',
1023            Z: 'TimezoneName',
1024            G: 'GmtOffset' 
1025        },
1026       
1027        shortcuts: {
1028            // date
1029            F: '%Y-%m-%d',
1030            // time
1031            T: '%H:%M:%S',
1032            X: '%H:%M:%S',
1033            // local format date
1034            x: '%m/%d/%y',
1035            D: '%m/%d/%y',
1036            // local format extended
1037            '#c': '%a %b %e %H:%M:%S %Y',
1038            // local format short
1039            v: '%e-%b-%Y',
1040            R: '%H:%M',
1041            r: '%I:%M:%S %p',
1042            // tab and newline
1043            t: '\t',
1044            n: '\n',
1045            '%': '%'
1046        }
1047    };
1048   
1049    /**
1050     * PHP format codes and shortcuts for strftime.
1051     *
1052     * A hash (object) of codes where each code must be an array where the first member is
1053     * the name of a Date.prototype or jsDate.prototype function to call
1054     * and optionally a second member indicating the number to pass to addZeros()
1055     *
1056     * <p>The following format codes are defined:</p>
1057     *
1058     * <pre class="code">
1059     * Code    Result                    Description
1060     * === Days ===       
1061     * %a      Sun through Sat           An abbreviated textual representation of the day
1062     * %A      Sunday - Saturday         A full textual representation of the day
1063     * %d      01 to 31                  Two-digit day of the month (with leading zeros)
1064     * %e      1 to 31                   Day of the month, with a space preceding single digits.
1065     * %j      001 to 366                Day of the year, 3 digits with leading zeros
1066     * %u      1 - 7 (Mon - Sun)         ISO-8601 numeric representation of the day of the week
1067     * %w      0 - 6 (Sun - Sat)         Numeric representation of the day of the week
1068     *                                 
1069     * === Week ===                     
1070     * %U      13                        Full Week number, starting with the first Sunday as the first week
1071     * %V      01 through 53             ISO-8601:1988 week number, starting with the first week of the year
1072     *                                   with at least 4 weekdays, with Monday being the start of the week
1073     * %W      46                        A numeric representation of the week of the year,
1074     *                                   starting with the first Monday as the first week
1075     * === Month ===                   
1076     * %b      Jan through Dec           Abbreviated month name, based on the locale
1077     * %B      January - December        Full month name, based on the locale
1078     * %h      Jan through Dec           Abbreviated month name, based on the locale (an alias of %b)
1079     * %m      01 - 12 (Jan - Dec)       Two digit representation of the month
1080     *
1081     * === Year ===                     
1082     * %C      19                        Two digit century (year/100, truncated to an integer)
1083     * %y      09 for 2009               Two digit year
1084     * %Y      2038                      Four digit year
1085     *
1086     * === Time ===                     
1087     * %H      00 through 23             Two digit representation of the hour in 24-hour format
1088     * %I      01 through 12             Two digit representation of the hour in 12-hour format
1089     * %l      1 through 12              Hour in 12-hour format, with a space preceeding single digits
1090     * %M      00 through 59             Two digit representation of the minute
1091     * %p      AM/PM                     UPPER-CASE 'AM' or 'PM' based on the given time
1092     * %P      am/pm                     lower-case 'am' or 'pm' based on the given time
1093     * %r      09:34:17 PM               Same as %I:%M:%S %p
1094     * %R      00:35                     Same as %H:%M
1095     * %S      00 through 59             Two digit representation of the second
1096     * %T      21:34:17                  Same as %H:%M:%S
1097     * %X      03:59:16                  Preferred time representation based on locale, without the date
1098     * %z      -0500 or EST              Either the time zone offset from UTC or the abbreviation
1099     * %Z      -0500 or EST              The time zone offset/abbreviation option NOT given by %z
1100     *
1101     * === Time and Date ===           
1102     * %D      02/05/09                  Same as %m/%d/%y
1103     * %F      2009-02-05                Same as %Y-%m-%d (commonly used in database datestamps)
1104     * %s      305815200                 Unix Epoch Time timestamp (same as the time() function)
1105     * %x      02/05/09                  Preferred date representation, without the time
1106     *
1107     * === Miscellaneous ===           
1108     * %n        ---                     A newline character (\n)
1109     * %t        ---                     A Tab character (\t)
1110     * %%        ---                     A literal percentage character (%)
1111     * </pre>
1112     */
1113 
1114    jsDate.formats.php = {
1115        codes: {
1116            //
1117            // 2-part regex matcher for format codes
1118            //
1119            // first match must be the character before the code (to account for escaping)
1120            // second match must be the format code character(s)
1121            //
1122            matcher: /()%((%|[a-z]))/i,
1123            // day
1124            a: 'AbbrDayName',
1125            A: 'DayName',
1126            d: 'Date.2',
1127            e: 'Date',
1128            j: 'DayOfYear.3',
1129            u: 'DayOfWeek',
1130            w: 'Day',
1131            // week
1132            U: 'FullWeekOfYear.2',
1133            V: 'IsoWeek.2',
1134            W: 'WeekOfYear.2',
1135            // month
1136            b: 'AbbrMonthName',
1137            B: 'MonthName',
1138            m: 'MonthNumber.2',
1139            h: 'AbbrMonthName',
1140            // year
1141            C: 'Century.2',
1142            y: 'ShortYear.2',
1143            Y: 'FullYear',
1144            // time
1145            H: 'Hours.2',
1146            I: 'Hours12.2',
1147            l: 'Hours12',
1148            p: 'AMPM',
1149            P: 'AmPm',
1150            M: 'Minutes.2',
1151            S: 'Seconds.2',
1152            s: 'Unix',
1153            O: 'TimezoneOffset',
1154            z: 'GmtOffset',
1155            Z: 'TimezoneAbbr'
1156        },
1157       
1158        shortcuts: {
1159            D: '%m/%d/%y',
1160            F: '%Y-%m-%d',
1161            T: '%H:%M:%S',
1162            X: '%H:%M:%S',
1163            x: '%m/%d/%y',
1164            R: '%H:%M',
1165            r: '%I:%M:%S %p',
1166            t: '\t',
1167            n: '\n',
1168            '%': '%'
1169        }
1170    };   
1171    //
1172    // Conceptually, the logic implemented here is similar to Ken Snyder's Date Instance Methods.
1173    // I use his idea of a set of parsers which can be regular expressions or functions,
1174    // iterating through those, and then seeing if Date.parse() will create a date.
1175    // The parser expressions and functions are a little different and some bugs have been
1176    // worked out.  Also, a lot of "pre-parsing" is done to fix implementation
1177    // variations of Date.parse() between browsers.
1178    //
1179    jsDate.createDate = function(date) {
1180        // if passing in multiple arguments, try Date constructor
1181        if (date == null) {
1182            return new Date();
1183        }
1184        // If the passed value is already a date object, return it
1185        if (date instanceof Date) {
1186            return date;
1187        }
1188        // if (typeof date == 'number') return new Date(date * 1000);
1189        // If the passed value is an integer, interpret it as a javascript timestamp
1190        if (typeof date == 'number') {
1191            return new Date(date);
1192        }
1193       
1194        // Before passing strings into Date.parse(), have to normalize them for certain conditions.
1195        // If strings are not formatted staccording to the EcmaScript spec, results from Date parse will be implementation dependent. 
1196        //
1197        // For example:
1198        //  * FF and Opera assume 2 digit dates are pre y2k, Chome assumes <50 is pre y2k, 50+ is 21st century. 
1199        //  * Chrome will correctly parse '1984-1-25' into localtime, FF and Opera will not parse.
1200        //  * Both FF, Chrome and Opera will parse '1984/1/25' into localtime.
1201       
1202        // remove leading and trailing spaces
1203        var parsable = String(date).replace(/^\s*(.+)\s*$/g, '$1');
1204       
1205        // replace dahses (-) with slashes (/) in dates like n[nnn]/n[n]/n[nnn]
1206        parsable = parsable.replace(/^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,4})/, "$1/$2/$3");
1207       
1208        /////////
1209        // Need to check for '15-Dec-09' also.
1210        // FF will not parse, but Chrome will.
1211        // Chrome will set date to 2009 as well.
1212        /////////
1213       
1214        // first check for 'dd-mmm-yyyy' or 'dd/mmm/yyyy' like '15-Dec-2010'
1215        parsable = parsable.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{4})/i, "$1 $2 $3");
1216       
1217        // Now check for 'dd-mmm-yy' or 'dd/mmm/yy' and normalize years to default century.
1218        var match = parsable.match(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i);
1219        if (match && match.length > 3) {
1220            var m3 = parseFloat(match[3]);
1221            var ny = jsDate.config.defaultCentury + m3;
1222            ny = String(ny);
1223           
1224            // now replace 2 digit year with 4 digit year
1225            parsable = parsable.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i, match[1] +' '+ match[2] +' '+ ny);
1226           
1227        }
1228       
1229        // Check for '1/19/70 8:14PM'
1230        // where starts with mm/dd/yy or yy/mm/dd and have something after
1231        // Check if 1st postiion is greater than 31, assume it is year.
1232        // Assme all 2 digit years are 1900's.
1233        // Finally, change them into US style mm/dd/yyyy representations.
1234        match = parsable.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})[^0-9]/);
1235       
1236        function h1(parsable, match) {
1237            var m1 = parseFloat(match[1]);
1238            var m2 = parseFloat(match[2]);
1239            var m3 = parseFloat(match[3]);
1240            var cent = jsDate.config.defaultCentury;
1241            var ny, nd, nm, str;
1242           
1243            if (m1 > 31) { // first number is a year
1244                nd = m3;
1245                nm = m2;
1246                ny = cent + m1;
1247            }
1248           
1249            else { // last number is the year
1250                nd = m2;
1251                nm = m1;
1252                ny = cent + m3;
1253            }
1254           
1255            str = nm+'/'+nd+'/'+ny;
1256           
1257            // now replace 2 digit year with 4 digit year
1258            return  parsable.replace(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})/, str);
1259       
1260        }
1261       
1262        if (match && match.length > 3) {
1263            parsable = h1(parsable, match);
1264        }
1265       
1266        // Now check for '1/19/70' with nothing after and do as above
1267        var match = parsable.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})$/);
1268       
1269        if (match && match.length > 3) {
1270            parsable = h1(parsable, match);
1271        }
1272               
1273       
1274        var i = 0;
1275        var length = jsDate.matchers.length;
1276        var pattern,
1277            ms,
1278            current = parsable;
1279        while (i < length) {
1280            ms = Date.parse(current);
1281            if (!isNaN(ms)) {
1282                return new Date(ms);
1283            }
1284            pattern = jsDate.matchers[i];
1285            if (typeof pattern == 'function') {
1286                var obj = pattern.call(jsDate, current);
1287                if (obj instanceof Date) {
1288                    return obj;
1289                }
1290            } else {
1291                current = parsable.replace(pattern[0], pattern[1]);
1292            }
1293            i++;
1294        }
1295        return NaN;
1296    };
1297   
1298
1299    /**
1300     * @static
1301     * Handy static utility function to return the number of days in a given month.
1302     * @param {Integer} year Year
1303     * @param {Integer} month Month (1-12)
1304     * @returns {Integer} Number of days in the month.
1305    */
1306    //
1307    // handy utility method Borrowed right from Ken Snyder's Date Instance Mehtods.
1308    //
1309    jsDate.daysInMonth = function(year, month) {
1310        if (month == 2) {
1311            return new Date(year, 1, 29).getDate() == 29 ? 29 : 28;
1312        }
1313        return [undefined,31,undefined,31,30,31,30,31,31,30,31,30,31][month];
1314    };
1315
1316
1317    //
1318    // An Array of regular expressions or functions that will attempt to match the date string.
1319    // Functions are called with scope of a jsDate instance.
1320    //
1321    jsDate.matchers = [
1322        // convert dd.mmm.yyyy to mm/dd/yyyy (world date to US date).
1323        [/(3[01]|[0-2]\d)\s*\.\s*(1[0-2]|0\d)\s*\.\s*([1-9]\d{3})/, '$2/$1/$3'],
1324        // convert yyyy-mm-dd to mm/dd/yyyy (ISO date to US date).
1325        [/([1-9]\d{3})\s*-\s*(1[0-2]|0\d)\s*-\s*(3[01]|[0-2]\d)/, '$2/$3/$1'],
1326        // Handle 12 hour or 24 hour time with milliseconds am/pm and optional date part.
1327        function(str) {
1328            var match = str.match(/^(?:(.+)\s+)?([012]?\d)(?:\s*\:\s*(\d\d))?(?:\s*\:\s*(\d\d(\.\d*)?))?\s*(am|pm)?\s*$/i);
1329            //                   opt. date      hour       opt. minute     opt. second       opt. msec   opt. am or pm
1330            if (match) {
1331                if (match[1]) {
1332                    var d = this.createDate(match[1]);
1333                    if (isNaN(d)) {
1334                        return;
1335                    }
1336                } else {
1337                    var d = new Date();
1338                    d.setMilliseconds(0);
1339                }
1340                var hour = parseFloat(match[2]);
1341                if (match[6]) {
1342                    hour = match[6].toLowerCase() == 'am' ? (hour == 12 ? 0 : hour) : (hour == 12 ? 12 : hour + 12);
1343                }
1344                d.setHours(hour, parseInt(match[3] || 0, 10), parseInt(match[4] || 0, 10), ((parseFloat(match[5] || 0)) || 0)*1000);
1345                return d;
1346            }
1347            else {
1348                return str;
1349            }
1350        },
1351        // Handle ISO timestamp with time zone.
1352        function(str) {
1353            var match = str.match(/^(?:(.+))[T|\s+]([012]\d)(?:\:(\d\d))(?:\:(\d\d))(?:\.\d+)([\+\-]\d\d\:\d\d)$/i);
1354            if (match) {
1355                if (match[1]) {
1356                    var d = this.createDate(match[1]);
1357                    if (isNaN(d)) {
1358                        return;
1359                    }
1360                } else {
1361                    var d = new Date();
1362                    d.setMilliseconds(0);
1363                }
1364                var hour = parseFloat(match[2]);
1365                d.setHours(hour, parseInt(match[3], 10), parseInt(match[4], 10), parseFloat(match[5])*1000);
1366                return d;
1367            }
1368            else {
1369                    return str;
1370            }
1371        },
1372        // Try to match ambiguous strings like 12/8/22.
1373        // Use FF date assumption that 2 digit years are 20th century (i.e. 1900's).
1374        // This may be redundant with pre processing of date already performed.
1375        function(str) {
1376            var match = str.match(/^([0-3]?\d)\s*[-\/.\s]{1}\s*([a-zA-Z]{3,9})\s*[-\/.\s]{1}\s*([0-3]?\d)$/);
1377            if (match) {
1378                var d = new Date();
1379                var cent = jsDate.config.defaultCentury;
1380                var m1 = parseFloat(match[1]);
1381                var m3 = parseFloat(match[3]);
1382                var ny, nd, nm;
1383                if (m1 > 31) { // first number is a year
1384                    nd = m3;
1385                    ny = cent + m1;
1386                }
1387               
1388                else { // last number is the year
1389                    nd = m1;
1390                    ny = cent + m3;
1391                }
1392               
1393                var nm = inArray(match[2], jsDate.regional[this.locale]["monthNamesShort"]);
1394               
1395                if (nm == -1) {
1396                    nm = inArray(match[2], jsDate.regional[this.locale]["monthNames"]);
1397                }
1398           
1399                d.setFullYear(ny, nm, nd);
1400                d.setHours(0,0,0,0);
1401                return d;
1402            }
1403           
1404            else {
1405                return str;
1406            }
1407        }     
1408    ];
1409
1410    //
1411    // I think John Reisig published this method on his blog, ejohn.
1412    //
1413    function inArray( elem, array ) {
1414        if ( array.indexOf ) {
1415            return array.indexOf( elem );
1416        }
1417
1418        for ( var i = 0, length = array.length; i < length; i++ ) {
1419            if ( array[ i ] === elem ) {
1420                return i;
1421            }
1422        }
1423
1424        return -1;
1425    }
1426   
1427    //
1428    // Thanks to Kangax, Christian Sciberras and Stack Overflow for this method.
1429    //
1430    function get_type(thing){
1431        if(thing===null) return "[object Null]"; // special case
1432        return Object.prototype.toString.call(thing);
1433    }
1434   
1435    $.jsDate = jsDate;
1436
1437})(jQuery);
Note: See TracBrowser for help on using the repository browser.