source: pro-violet-viettel/docs/template/assets/js/uncompressed/date-time/moment.js @ 400

Last change on this file since 400 was 400, checked in by dungnv, 11 years ago
  • Property svn:mime-type set to text/plain
File size: 42.9 KB
RevLine 
[400]1// moment.js
2// version : 2.0.0
3// author : Tim Wood
4// license : MIT
5// momentjs.com
6
7(function (undefined) {
8
9    /************************************
10        Constants
11    ************************************/
12
13    var moment,
14        VERSION = "2.0.0",
15        round = Math.round, i,
16        // internal storage for language config files
17        languages = {},
18
19        // check for nodeJS
20        hasModule = (typeof module !== 'undefined' && module.exports),
21
22        // ASP.NET json date format regex
23        aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,
24
25        // format tokens
26        formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g,
27        localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,
28
29        // parsing tokens
30        parseMultipleFormatChunker = /([0-9a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)/gi,
31
32        // parsing token regexes
33        parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
34        parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
35        parseTokenThreeDigits = /\d{3}/, // 000 - 999
36        parseTokenFourDigits = /\d{1,4}/, // 0 - 9999
37        parseTokenSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
38        parseTokenWord = /[0-9]*[a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF]+\s*?[\u0600-\u06FF]+/i, // any word (or two) characters or numbers including two word month in arabic.
39        parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z
40        parseTokenT = /T/i, // T (ISO seperator)
41        parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
42
43        // preliminary iso regex
44        // 0000-00-00 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000
45        isoRegex = /^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/,
46        isoFormat = 'YYYY-MM-DDTHH:mm:ssZ',
47
48        // iso time formats and regexes
49        isoTimes = [
50            ['HH:mm:ss.S', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/],
51            ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/],
52            ['HH:mm', /(T| )\d\d:\d\d/],
53            ['HH', /(T| )\d\d/]
54        ],
55
56        // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"]
57        parseTimezoneChunker = /([\+\-]|\d\d)/gi,
58
59        // getter and setter names
60        proxyGettersAndSetters = 'Month|Date|Hours|Minutes|Seconds|Milliseconds'.split('|'),
61        unitMillisecondFactors = {
62            'Milliseconds' : 1,
63            'Seconds' : 1e3,
64            'Minutes' : 6e4,
65            'Hours' : 36e5,
66            'Days' : 864e5,
67            'Months' : 2592e6,
68            'Years' : 31536e6
69        },
70
71        // format function strings
72        formatFunctions = {},
73
74        // tokens to ordinalize and pad
75        ordinalizeTokens = 'DDD w W M D d'.split(' '),
76        paddedTokens = 'M D H h m s w W'.split(' '),
77
78        formatTokenFunctions = {
79            M    : function () {
80                return this.month() + 1;
81            },
82            MMM  : function (format) {
83                return this.lang().monthsShort(this, format);
84            },
85            MMMM : function (format) {
86                return this.lang().months(this, format);
87            },
88            D    : function () {
89                return this.date();
90            },
91            DDD  : function () {
92                return this.dayOfYear();
93            },
94            d    : function () {
95                return this.day();
96            },
97            dd   : function (format) {
98                return this.lang().weekdaysMin(this, format);
99            },
100            ddd  : function (format) {
101                return this.lang().weekdaysShort(this, format);
102            },
103            dddd : function (format) {
104                return this.lang().weekdays(this, format);
105            },
106            w    : function () {
107                return this.week();
108            },
109            W    : function () {
110                return this.isoWeek();
111            },
112            YY   : function () {
113                return leftZeroFill(this.year() % 100, 2);
114            },
115            YYYY : function () {
116                return leftZeroFill(this.year(), 4);
117            },
118            YYYYY : function () {
119                return leftZeroFill(this.year(), 5);
120            },
121            a    : function () {
122                return this.lang().meridiem(this.hours(), this.minutes(), true);
123            },
124            A    : function () {
125                return this.lang().meridiem(this.hours(), this.minutes(), false);
126            },
127            H    : function () {
128                return this.hours();
129            },
130            h    : function () {
131                return this.hours() % 12 || 12;
132            },
133            m    : function () {
134                return this.minutes();
135            },
136            s    : function () {
137                return this.seconds();
138            },
139            S    : function () {
140                return ~~(this.milliseconds() / 100);
141            },
142            SS   : function () {
143                return leftZeroFill(~~(this.milliseconds() / 10), 2);
144            },
145            SSS  : function () {
146                return leftZeroFill(this.milliseconds(), 3);
147            },
148            Z    : function () {
149                var a = -this.zone(),
150                    b = "+";
151                if (a < 0) {
152                    a = -a;
153                    b = "-";
154                }
155                return b + leftZeroFill(~~(a / 60), 2) + ":" + leftZeroFill(~~a % 60, 2);
156            },
157            ZZ   : function () {
158                var a = -this.zone(),
159                    b = "+";
160                if (a < 0) {
161                    a = -a;
162                    b = "-";
163                }
164                return b + leftZeroFill(~~(10 * a / 6), 4);
165            },
166            X    : function () {
167                return this.unix();
168            }
169        };
170
171    function padToken(func, count) {
172        return function (a) {
173            return leftZeroFill(func.call(this, a), count);
174        };
175    }
176    function ordinalizeToken(func) {
177        return function (a) {
178            return this.lang().ordinal(func.call(this, a));
179        };
180    }
181
182    while (ordinalizeTokens.length) {
183        i = ordinalizeTokens.pop();
184        formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i]);
185    }
186    while (paddedTokens.length) {
187        i = paddedTokens.pop();
188        formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2);
189    }
190    formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3);
191
192
193    /************************************
194        Constructors
195    ************************************/
196
197    function Language() {
198
199    }
200
201    // Moment prototype object
202    function Moment(config) {
203        extend(this, config);
204    }
205
206    // Duration Constructor
207    function Duration(duration) {
208        var data = this._data = {},
209            years = duration.years || duration.year || duration.y || 0,
210            months = duration.months || duration.month || duration.M || 0,
211            weeks = duration.weeks || duration.week || duration.w || 0,
212            days = duration.days || duration.day || duration.d || 0,
213            hours = duration.hours || duration.hour || duration.h || 0,
214            minutes = duration.minutes || duration.minute || duration.m || 0,
215            seconds = duration.seconds || duration.second || duration.s || 0,
216            milliseconds = duration.milliseconds || duration.millisecond || duration.ms || 0;
217
218        // representation for dateAddRemove
219        this._milliseconds = milliseconds +
220            seconds * 1e3 + // 1000
221            minutes * 6e4 + // 1000 * 60
222            hours * 36e5; // 1000 * 60 * 60
223        // Because of dateAddRemove treats 24 hours as different from a
224        // day when working around DST, we need to store them separately
225        this._days = days +
226            weeks * 7;
227        // It is impossible translate months into days without knowing
228        // which months you are are talking about, so we have to store
229        // it separately.
230        this._months = months +
231            years * 12;
232
233        // The following code bubbles up values, see the tests for
234        // examples of what that means.
235        data.milliseconds = milliseconds % 1000;
236        seconds += absRound(milliseconds / 1000);
237
238        data.seconds = seconds % 60;
239        minutes += absRound(seconds / 60);
240
241        data.minutes = minutes % 60;
242        hours += absRound(minutes / 60);
243
244        data.hours = hours % 24;
245        days += absRound(hours / 24);
246
247        days += weeks * 7;
248        data.days = days % 30;
249
250        months += absRound(days / 30);
251
252        data.months = months % 12;
253        years += absRound(months / 12);
254
255        data.years = years;
256    }
257
258
259    /************************************
260        Helpers
261    ************************************/
262
263
264    function extend(a, b) {
265        for (var i in b) {
266            if (b.hasOwnProperty(i)) {
267                a[i] = b[i];
268            }
269        }
270        return a;
271    }
272
273    function absRound(number) {
274        if (number < 0) {
275            return Math.ceil(number);
276        } else {
277            return Math.floor(number);
278        }
279    }
280
281    // left zero fill a number
282    // see http://jsperf.com/left-zero-filling for performance comparison
283    function leftZeroFill(number, targetLength) {
284        var output = number + '';
285        while (output.length < targetLength) {
286            output = '0' + output;
287        }
288        return output;
289    }
290
291    // helper function for _.addTime and _.subtractTime
292    function addOrSubtractDurationFromMoment(mom, duration, isAdding) {
293        var ms = duration._milliseconds,
294            d = duration._days,
295            M = duration._months,
296            currentDate;
297
298        if (ms) {
299            mom._d.setTime(+mom + ms * isAdding);
300        }
301        if (d) {
302            mom.date(mom.date() + d * isAdding);
303        }
304        if (M) {
305            currentDate = mom.date();
306            mom.date(1)
307                .month(mom.month() + M * isAdding)
308                .date(Math.min(currentDate, mom.daysInMonth()));
309        }
310    }
311
312    // check if is an array
313    function isArray(input) {
314        return Object.prototype.toString.call(input) === '[object Array]';
315    }
316
317    // compare two arrays, return the number of differences
318    function compareArrays(array1, array2) {
319        var len = Math.min(array1.length, array2.length),
320            lengthDiff = Math.abs(array1.length - array2.length),
321            diffs = 0,
322            i;
323        for (i = 0; i < len; i++) {
324            if (~~array1[i] !== ~~array2[i]) {
325                diffs++;
326            }
327        }
328        return diffs + lengthDiff;
329    }
330
331
332    /************************************
333        Languages
334    ************************************/
335
336
337    Language.prototype = {
338        set : function (config) {
339            var prop, i;
340            for (i in config) {
341                prop = config[i];
342                if (typeof prop === 'function') {
343                    this[i] = prop;
344                } else {
345                    this['_' + i] = prop;
346                }
347            }
348        },
349
350        _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
351        months : function (m) {
352            return this._months[m.month()];
353        },
354
355        _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),
356        monthsShort : function (m) {
357            return this._monthsShort[m.month()];
358        },
359
360        monthsParse : function (monthName) {
361            var i, mom, regex, output;
362
363            if (!this._monthsParse) {
364                this._monthsParse = [];
365            }
366
367            for (i = 0; i < 12; i++) {
368                // make the regex if we don't have it already
369                if (!this._monthsParse[i]) {
370                    mom = moment([2000, i]);
371                    regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
372                    this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
373                }
374                // test the regex
375                if (this._monthsParse[i].test(monthName)) {
376                    return i;
377                }
378            }
379        },
380
381        _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
382        weekdays : function (m) {
383            return this._weekdays[m.day()];
384        },
385
386        _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),
387        weekdaysShort : function (m) {
388            return this._weekdaysShort[m.day()];
389        },
390
391        _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"),
392        weekdaysMin : function (m) {
393            return this._weekdaysMin[m.day()];
394        },
395
396        _longDateFormat : {
397            LT : "h:mm A",
398            L : "MM/DD/YYYY",
399            LL : "MMMM D YYYY",
400            LLL : "MMMM D YYYY LT",
401            LLLL : "dddd, MMMM D YYYY LT"
402        },
403        longDateFormat : function (key) {
404            var output = this._longDateFormat[key];
405            if (!output && this._longDateFormat[key.toUpperCase()]) {
406                output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) {
407                    return val.slice(1);
408                });
409                this._longDateFormat[key] = output;
410            }
411            return output;
412        },
413
414        meridiem : function (hours, minutes, isLower) {
415            if (hours > 11) {
416                return isLower ? 'pm' : 'PM';
417            } else {
418                return isLower ? 'am' : 'AM';
419            }
420        },
421
422        _calendar : {
423            sameDay : '[Today at] LT',
424            nextDay : '[Tomorrow at] LT',
425            nextWeek : 'dddd [at] LT',
426            lastDay : '[Yesterday at] LT',
427            lastWeek : '[last] dddd [at] LT',
428            sameElse : 'L'
429        },
430        calendar : function (key, mom) {
431            var output = this._calendar[key];
432            return typeof output === 'function' ? output.apply(mom) : output;
433        },
434
435        _relativeTime : {
436            future : "in %s",
437            past : "%s ago",
438            s : "a few seconds",
439            m : "a minute",
440            mm : "%d minutes",
441            h : "an hour",
442            hh : "%d hours",
443            d : "a day",
444            dd : "%d days",
445            M : "a month",
446            MM : "%d months",
447            y : "a year",
448            yy : "%d years"
449        },
450        relativeTime : function (number, withoutSuffix, string, isFuture) {
451            var output = this._relativeTime[string];
452            return (typeof output === 'function') ?
453                output(number, withoutSuffix, string, isFuture) :
454                output.replace(/%d/i, number);
455        },
456        pastFuture : function (diff, output) {
457            var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
458            return typeof format === 'function' ? format(output) : format.replace(/%s/i, output);
459        },
460
461        ordinal : function (number) {
462            return this._ordinal.replace("%d", number);
463        },
464        _ordinal : "%d",
465
466        preparse : function (string) {
467            return string;
468        },
469
470        postformat : function (string) {
471            return string;
472        },
473
474        week : function (mom) {
475            return weekOfYear(mom, this._week.dow, this._week.doy);
476        },
477        _week : {
478            dow : 0, // Sunday is the first day of the week.
479            doy : 6  // The week that contains Jan 1st is the first week of the year.
480        }
481    };
482
483    // Loads a language definition into the `languages` cache.  The function
484    // takes a key and optionally values.  If not in the browser and no values
485    // are provided, it will load the language file module.  As a convenience,
486    // this function also returns the language values.
487    function loadLang(key, values) {
488        values.abbr = key;
489        if (!languages[key]) {
490            languages[key] = new Language();
491        }
492        languages[key].set(values);
493        return languages[key];
494    }
495
496    // Determines which language definition to use and returns it.
497    //
498    // With no parameters, it will return the global language.  If you
499    // pass in a language key, such as 'en', it will return the
500    // definition for 'en', so long as 'en' has already been loaded using
501    // moment.lang.
502    function getLangDefinition(key) {
503        if (!key) {
504            return moment.fn._lang;
505        }
506        if (!languages[key] && hasModule) {
507            require('./lang/' + key);
508        }
509        return languages[key];
510    }
511
512
513    /************************************
514        Formatting
515    ************************************/
516
517
518    function removeFormattingTokens(input) {
519        if (input.match(/\[.*\]/)) {
520            return input.replace(/^\[|\]$/g, "");
521        }
522        return input.replace(/\\/g, "");
523    }
524
525    function makeFormatFunction(format) {
526        var array = format.match(formattingTokens), i, length;
527
528        for (i = 0, length = array.length; i < length; i++) {
529            if (formatTokenFunctions[array[i]]) {
530                array[i] = formatTokenFunctions[array[i]];
531            } else {
532                array[i] = removeFormattingTokens(array[i]);
533            }
534        }
535
536        return function (mom) {
537            var output = "";
538            for (i = 0; i < length; i++) {
539                output += typeof array[i].call === 'function' ? array[i].call(mom, format) : array[i];
540            }
541            return output;
542        };
543    }
544
545    // format date using native date object
546    function formatMoment(m, format) {
547        var i = 5;
548
549        function replaceLongDateFormatTokens(input) {
550            return m.lang().longDateFormat(input) || input;
551        }
552
553        while (i-- && localFormattingTokens.test(format)) {
554            format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
555        }
556
557        if (!formatFunctions[format]) {
558            formatFunctions[format] = makeFormatFunction(format);
559        }
560
561        return formatFunctions[format](m);
562    }
563
564
565    /************************************
566        Parsing
567    ************************************/
568
569
570    // get the regex to find the next token
571    function getParseRegexForToken(token) {
572        switch (token) {
573        case 'DDDD':
574            return parseTokenThreeDigits;
575        case 'YYYY':
576            return parseTokenFourDigits;
577        case 'YYYYY':
578            return parseTokenSixDigits;
579        case 'S':
580        case 'SS':
581        case 'SSS':
582        case 'DDD':
583            return parseTokenOneToThreeDigits;
584        case 'MMM':
585        case 'MMMM':
586        case 'dd':
587        case 'ddd':
588        case 'dddd':
589        case 'a':
590        case 'A':
591            return parseTokenWord;
592        case 'X':
593            return parseTokenTimestampMs;
594        case 'Z':
595        case 'ZZ':
596            return parseTokenTimezone;
597        case 'T':
598            return parseTokenT;
599        case 'MM':
600        case 'DD':
601        case 'YY':
602        case 'HH':
603        case 'hh':
604        case 'mm':
605        case 'ss':
606        case 'M':
607        case 'D':
608        case 'd':
609        case 'H':
610        case 'h':
611        case 'm':
612        case 's':
613            return parseTokenOneOrTwoDigits;
614        default :
615            return new RegExp(token.replace('\\', ''));
616        }
617    }
618
619    // function to convert string input to date
620    function addTimeToArrayFromToken(token, input, config) {
621        var a, b,
622            datePartArray = config._a;
623
624        switch (token) {
625        // MONTH
626        case 'M' : // fall through to MM
627        case 'MM' :
628            datePartArray[1] = (input == null) ? 0 : ~~input - 1;
629            break;
630        case 'MMM' : // fall through to MMMM
631        case 'MMMM' :
632            a = getLangDefinition(config._l).monthsParse(input);
633            // if we didn't find a month name, mark the date as invalid.
634            if (a != null) {
635                datePartArray[1] = a;
636            } else {
637                config._isValid = false;
638            }
639            break;
640        // DAY OF MONTH
641        case 'D' : // fall through to DDDD
642        case 'DD' : // fall through to DDDD
643        case 'DDD' : // fall through to DDDD
644        case 'DDDD' :
645            if (input != null) {
646                datePartArray[2] = ~~input;
647            }
648            break;
649        // YEAR
650        case 'YY' :
651            datePartArray[0] = ~~input + (~~input > 68 ? 1900 : 2000);
652            break;
653        case 'YYYY' :
654        case 'YYYYY' :
655            datePartArray[0] = ~~input;
656            break;
657        // AM / PM
658        case 'a' : // fall through to A
659        case 'A' :
660            config._isPm = ((input + '').toLowerCase() === 'pm');
661            break;
662        // 24 HOUR
663        case 'H' : // fall through to hh
664        case 'HH' : // fall through to hh
665        case 'h' : // fall through to hh
666        case 'hh' :
667            datePartArray[3] = ~~input;
668            break;
669        // MINUTE
670        case 'm' : // fall through to mm
671        case 'mm' :
672            datePartArray[4] = ~~input;
673            break;
674        // SECOND
675        case 's' : // fall through to ss
676        case 'ss' :
677            datePartArray[5] = ~~input;
678            break;
679        // MILLISECOND
680        case 'S' :
681        case 'SS' :
682        case 'SSS' :
683            datePartArray[6] = ~~ (('0.' + input) * 1000);
684            break;
685        // UNIX TIMESTAMP WITH MS
686        case 'X':
687            config._d = new Date(parseFloat(input) * 1000);
688            break;
689        // TIMEZONE
690        case 'Z' : // fall through to ZZ
691        case 'ZZ' :
692            config._useUTC = true;
693            a = (input + '').match(parseTimezoneChunker);
694            if (a && a[1]) {
695                config._tzh = ~~a[1];
696            }
697            if (a && a[2]) {
698                config._tzm = ~~a[2];
699            }
700            // reverse offsets
701            if (a && a[0] === '+') {
702                config._tzh = -config._tzh;
703                config._tzm = -config._tzm;
704            }
705            break;
706        }
707
708        // if the input is null, the date is not valid
709        if (input == null) {
710            config._isValid = false;
711        }
712    }
713
714    // convert an array to a date.
715    // the array should mirror the parameters below
716    // note: all values past the year are optional and will default to the lowest possible value.
717    // [year, month, day , hour, minute, second, millisecond]
718    function dateFromArray(config) {
719        var i, date, input = [];
720
721        if (config._d) {
722            return;
723        }
724
725        for (i = 0; i < 7; i++) {
726            config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
727        }
728
729        // add the offsets to the time to be parsed so that we can have a clean array for checking isValid
730        input[3] += config._tzh || 0;
731        input[4] += config._tzm || 0;
732
733        date = new Date(0);
734
735        if (config._useUTC) {
736            date.setUTCFullYear(input[0], input[1], input[2]);
737            date.setUTCHours(input[3], input[4], input[5], input[6]);
738        } else {
739            date.setFullYear(input[0], input[1], input[2]);
740            date.setHours(input[3], input[4], input[5], input[6]);
741        }
742
743        config._d = date;
744    }
745
746    // date from string and format string
747    function makeDateFromStringAndFormat(config) {
748        // This array is used to make a Date, either with `new Date` or `Date.UTC`
749        var tokens = config._f.match(formattingTokens),
750            string = config._i,
751            i, parsedInput;
752
753        config._a = [];
754
755        for (i = 0; i < tokens.length; i++) {
756            parsedInput = (getParseRegexForToken(tokens[i]).exec(string) || [])[0];
757            if (parsedInput) {
758                string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
759            }
760            // don't parse if its not a known token
761            if (formatTokenFunctions[tokens[i]]) {
762                addTimeToArrayFromToken(tokens[i], parsedInput, config);
763            }
764        }
765        // handle am pm
766        if (config._isPm && config._a[3] < 12) {
767            config._a[3] += 12;
768        }
769        // if is 12 am, change hours to 0
770        if (config._isPm === false && config._a[3] === 12) {
771            config._a[3] = 0;
772        }
773        // return
774        dateFromArray(config);
775    }
776
777    // date from string and array of format strings
778    function makeDateFromStringAndArray(config) {
779        var tempConfig,
780            tempMoment,
781            bestMoment,
782
783            scoreToBeat = 99,
784            i,
785            currentDate,
786            currentScore;
787
788        while (config._f.length) {
789            tempConfig = extend({}, config);
790            tempConfig._f = config._f.pop();
791            makeDateFromStringAndFormat(tempConfig);
792            tempMoment = new Moment(tempConfig);
793
794            if (tempMoment.isValid()) {
795                bestMoment = tempMoment;
796                break;
797            }
798
799            currentScore = compareArrays(tempConfig._a, tempMoment.toArray());
800
801            if (currentScore < scoreToBeat) {
802                scoreToBeat = currentScore;
803                bestMoment = tempMoment;
804            }
805        }
806
807        extend(config, bestMoment);
808    }
809
810    // date from iso format
811    function makeDateFromString(config) {
812        var i,
813            string = config._i;
814        if (isoRegex.exec(string)) {
815            config._f = 'YYYY-MM-DDT';
816            for (i = 0; i < 4; i++) {
817                if (isoTimes[i][1].exec(string)) {
818                    config._f += isoTimes[i][0];
819                    break;
820                }
821            }
822            if (parseTokenTimezone.exec(string)) {
823                config._f += " Z";
824            }
825            makeDateFromStringAndFormat(config);
826        } else {
827            config._d = new Date(string);
828        }
829    }
830
831    function makeDateFromInput(config) {
832        var input = config._i,
833            matched = aspNetJsonRegex.exec(input);
834
835        if (input === undefined) {
836            config._d = new Date();
837        } else if (matched) {
838            config._d = new Date(+matched[1]);
839        } else if (typeof input === 'string') {
840            makeDateFromString(config);
841        } else if (isArray(input)) {
842            config._a = input.slice(0);
843            dateFromArray(config);
844        } else {
845            config._d = input instanceof Date ? new Date(+input) : new Date(input);
846        }
847    }
848
849
850    /************************************
851        Relative Time
852    ************************************/
853
854
855    // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
856    function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) {
857        return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
858    }
859
860    function relativeTime(milliseconds, withoutSuffix, lang) {
861        var seconds = round(Math.abs(milliseconds) / 1000),
862            minutes = round(seconds / 60),
863            hours = round(minutes / 60),
864            days = round(hours / 24),
865            years = round(days / 365),
866            args = seconds < 45 && ['s', seconds] ||
867                minutes === 1 && ['m'] ||
868                minutes < 45 && ['mm', minutes] ||
869                hours === 1 && ['h'] ||
870                hours < 22 && ['hh', hours] ||
871                days === 1 && ['d'] ||
872                days <= 25 && ['dd', days] ||
873                days <= 45 && ['M'] ||
874                days < 345 && ['MM', round(days / 30)] ||
875                years === 1 && ['y'] || ['yy', years];
876        args[2] = withoutSuffix;
877        args[3] = milliseconds > 0;
878        args[4] = lang;
879        return substituteTimeAgo.apply({}, args);
880    }
881
882
883    /************************************
884        Week of Year
885    ************************************/
886
887
888    // firstDayOfWeek       0 = sun, 6 = sat
889    //                      the day of the week that starts the week
890    //                      (usually sunday or monday)
891    // firstDayOfWeekOfYear 0 = sun, 6 = sat
892    //                      the first week is the week that contains the first
893    //                      of this day of the week
894    //                      (eg. ISO weeks use thursday (4))
895    function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
896        var end = firstDayOfWeekOfYear - firstDayOfWeek,
897            daysToDayOfWeek = firstDayOfWeekOfYear - mom.day();
898
899
900        if (daysToDayOfWeek > end) {
901            daysToDayOfWeek -= 7;
902        }
903
904        if (daysToDayOfWeek < end - 7) {
905            daysToDayOfWeek += 7;
906        }
907
908        return Math.ceil(moment(mom).add('d', daysToDayOfWeek).dayOfYear() / 7);
909    }
910
911
912    /************************************
913        Top Level Functions
914    ************************************/
915
916    function makeMoment(config) {
917        var input = config._i,
918            format = config._f;
919
920        if (input === null || input === '') {
921            return null;
922        }
923
924        if (typeof input === 'string') {
925            config._i = input = getLangDefinition().preparse(input);
926        }
927
928        if (moment.isMoment(input)) {
929            config = extend({}, input);
930            config._d = new Date(+input._d);
931        } else if (format) {
932            if (isArray(format)) {
933                makeDateFromStringAndArray(config);
934            } else {
935                makeDateFromStringAndFormat(config);
936            }
937        } else {
938            makeDateFromInput(config);
939        }
940
941        return new Moment(config);
942    }
943
944    moment = function (input, format, lang) {
945        return makeMoment({
946            _i : input,
947            _f : format,
948            _l : lang,
949            _isUTC : false
950        });
951    };
952
953    // creating with utc
954    moment.utc = function (input, format, lang) {
955        return makeMoment({
956            _useUTC : true,
957            _isUTC : true,
958            _l : lang,
959            _i : input,
960            _f : format
961        });
962    };
963
964    // creating with unix timestamp (in seconds)
965    moment.unix = function (input) {
966        return moment(input * 1000);
967    };
968
969    // duration
970    moment.duration = function (input, key) {
971        var isDuration = moment.isDuration(input),
972            isNumber = (typeof input === 'number'),
973            duration = (isDuration ? input._data : (isNumber ? {} : input)),
974            ret;
975
976        if (isNumber) {
977            if (key) {
978                duration[key] = input;
979            } else {
980                duration.milliseconds = input;
981            }
982        }
983
984        ret = new Duration(duration);
985
986        if (isDuration && input.hasOwnProperty('_lang')) {
987            ret._lang = input._lang;
988        }
989
990        return ret;
991    };
992
993    // version number
994    moment.version = VERSION;
995
996    // default format
997    moment.defaultFormat = isoFormat;
998
999    // This function will load languages and then set the global language.  If
1000    // no arguments are passed in, it will simply return the current global
1001    // language key.
1002    moment.lang = function (key, values) {
1003        var i;
1004
1005        if (!key) {
1006            return moment.fn._lang._abbr;
1007        }
1008        if (values) {
1009            loadLang(key, values);
1010        } else if (!languages[key]) {
1011            getLangDefinition(key);
1012        }
1013        moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key);
1014    };
1015
1016    // returns language data
1017    moment.langData = function (key) {
1018        if (key && key._lang && key._lang._abbr) {
1019            key = key._lang._abbr;
1020        }
1021        return getLangDefinition(key);
1022    };
1023
1024    // compare moment object
1025    moment.isMoment = function (obj) {
1026        return obj instanceof Moment;
1027    };
1028
1029    // for typechecking Duration objects
1030    moment.isDuration = function (obj) {
1031        return obj instanceof Duration;
1032    };
1033
1034
1035    /************************************
1036        Moment Prototype
1037    ************************************/
1038
1039
1040    moment.fn = Moment.prototype = {
1041
1042        clone : function () {
1043            return moment(this);
1044        },
1045
1046        valueOf : function () {
1047            return +this._d;
1048        },
1049
1050        unix : function () {
1051            return Math.floor(+this._d / 1000);
1052        },
1053
1054        toString : function () {
1055            return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ");
1056        },
1057
1058        toDate : function () {
1059            return this._d;
1060        },
1061
1062        toJSON : function () {
1063            return moment.utc(this).format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
1064        },
1065
1066        toArray : function () {
1067            var m = this;
1068            return [
1069                m.year(),
1070                m.month(),
1071                m.date(),
1072                m.hours(),
1073                m.minutes(),
1074                m.seconds(),
1075                m.milliseconds()
1076            ];
1077        },
1078
1079        isValid : function () {
1080            if (this._isValid == null) {
1081                if (this._a) {
1082                    this._isValid = !compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray());
1083                } else {
1084                    this._isValid = !isNaN(this._d.getTime());
1085                }
1086            }
1087            return !!this._isValid;
1088        },
1089
1090        utc : function () {
1091            this._isUTC = true;
1092            return this;
1093        },
1094
1095        local : function () {
1096            this._isUTC = false;
1097            return this;
1098        },
1099
1100        format : function (inputString) {
1101            var output = formatMoment(this, inputString || moment.defaultFormat);
1102            return this.lang().postformat(output);
1103        },
1104
1105        add : function (input, val) {
1106            var dur;
1107            // switch args to support add('s', 1) and add(1, 's')
1108            if (typeof input === 'string') {
1109                dur = moment.duration(+val, input);
1110            } else {
1111                dur = moment.duration(input, val);
1112            }
1113            addOrSubtractDurationFromMoment(this, dur, 1);
1114            return this;
1115        },
1116
1117        subtract : function (input, val) {
1118            var dur;
1119            // switch args to support subtract('s', 1) and subtract(1, 's')
1120            if (typeof input === 'string') {
1121                dur = moment.duration(+val, input);
1122            } else {
1123                dur = moment.duration(input, val);
1124            }
1125            addOrSubtractDurationFromMoment(this, dur, -1);
1126            return this;
1127        },
1128
1129        diff : function (input, units, asFloat) {
1130            var that = this._isUTC ? moment(input).utc() : moment(input).local(),
1131                zoneDiff = (this.zone() - that.zone()) * 6e4,
1132                diff, output;
1133
1134            if (units) {
1135                // standardize on singular form
1136                units = units.replace(/s$/, '');
1137            }
1138
1139            if (units === 'year' || units === 'month') {
1140                diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2
1141                output = ((this.year() - that.year()) * 12) + (this.month() - that.month());
1142                output += ((this - moment(this).startOf('month')) - (that - moment(that).startOf('month'))) / diff;
1143                if (units === 'year') {
1144                    output = output / 12;
1145                }
1146            } else {
1147                diff = (this - that) - zoneDiff;
1148                output = units === 'second' ? diff / 1e3 : // 1000
1149                    units === 'minute' ? diff / 6e4 : // 1000 * 60
1150                    units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60
1151                    units === 'day' ? diff / 864e5 : // 1000 * 60 * 60 * 24
1152                    units === 'week' ? diff / 6048e5 : // 1000 * 60 * 60 * 24 * 7
1153                    diff;
1154            }
1155            return asFloat ? output : absRound(output);
1156        },
1157
1158        from : function (time, withoutSuffix) {
1159            return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix);
1160        },
1161
1162        fromNow : function (withoutSuffix) {
1163            return this.from(moment(), withoutSuffix);
1164        },
1165
1166        calendar : function () {
1167            var diff = this.diff(moment().startOf('day'), 'days', true),
1168                format = diff < -6 ? 'sameElse' :
1169                diff < -1 ? 'lastWeek' :
1170                diff < 0 ? 'lastDay' :
1171                diff < 1 ? 'sameDay' :
1172                diff < 2 ? 'nextDay' :
1173                diff < 7 ? 'nextWeek' : 'sameElse';
1174            return this.format(this.lang().calendar(format, this));
1175        },
1176
1177        isLeapYear : function () {
1178            var year = this.year();
1179            return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
1180        },
1181
1182        isDST : function () {
1183            return (this.zone() < moment([this.year()]).zone() ||
1184                this.zone() < moment([this.year(), 5]).zone());
1185        },
1186
1187        day : function (input) {
1188            var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
1189            return input == null ? day :
1190                this.add({ d : input - day });
1191        },
1192
1193        startOf: function (units) {
1194            units = units.replace(/s$/, '');
1195            // the following switch intentionally omits break keywords
1196            // to utilize falling through the cases.
1197            switch (units) {
1198            case 'year':
1199                this.month(0);
1200                /* falls through */
1201            case 'month':
1202                this.date(1);
1203                /* falls through */
1204            case 'week':
1205            case 'day':
1206                this.hours(0);
1207                /* falls through */
1208            case 'hour':
1209                this.minutes(0);
1210                /* falls through */
1211            case 'minute':
1212                this.seconds(0);
1213                /* falls through */
1214            case 'second':
1215                this.milliseconds(0);
1216                /* falls through */
1217            }
1218
1219            // weeks are a special case
1220            if (units === 'week') {
1221                this.day(0);
1222            }
1223
1224            return this;
1225        },
1226
1227        endOf: function (units) {
1228            return this.startOf(units).add(units.replace(/s?$/, 's'), 1).subtract('ms', 1);
1229        },
1230
1231        isAfter: function (input, units) {
1232            units = typeof units !== 'undefined' ? units : 'millisecond';
1233            return +this.clone().startOf(units) > +moment(input).startOf(units);
1234        },
1235
1236        isBefore: function (input, units) {
1237            units = typeof units !== 'undefined' ? units : 'millisecond';
1238            return +this.clone().startOf(units) < +moment(input).startOf(units);
1239        },
1240
1241        isSame: function (input, units) {
1242            units = typeof units !== 'undefined' ? units : 'millisecond';
1243            return +this.clone().startOf(units) === +moment(input).startOf(units);
1244        },
1245
1246        zone : function () {
1247            return this._isUTC ? 0 : this._d.getTimezoneOffset();
1248        },
1249
1250        daysInMonth : function () {
1251            return moment.utc([this.year(), this.month() + 1, 0]).date();
1252        },
1253
1254        dayOfYear : function (input) {
1255            var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1;
1256            return input == null ? dayOfYear : this.add("d", (input - dayOfYear));
1257        },
1258
1259        isoWeek : function (input) {
1260            var week = weekOfYear(this, 1, 4);
1261            return input == null ? week : this.add("d", (input - week) * 7);
1262        },
1263
1264        week : function (input) {
1265            var week = this.lang().week(this);
1266            return input == null ? week : this.add("d", (input - week) * 7);
1267        },
1268
1269        // If passed a language key, it will set the language for this
1270        // instance.  Otherwise, it will return the language configuration
1271        // variables for this instance.
1272        lang : function (key) {
1273            if (key === undefined) {
1274                return this._lang;
1275            } else {
1276                this._lang = getLangDefinition(key);
1277                return this;
1278            }
1279        }
1280    };
1281
1282    // helper for adding shortcuts
1283    function makeGetterAndSetter(name, key) {
1284        moment.fn[name] = moment.fn[name + 's'] = function (input) {
1285            var utc = this._isUTC ? 'UTC' : '';
1286            if (input != null) {
1287                this._d['set' + utc + key](input);
1288                return this;
1289            } else {
1290                return this._d['get' + utc + key]();
1291            }
1292        };
1293    }
1294
1295    // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds)
1296    for (i = 0; i < proxyGettersAndSetters.length; i ++) {
1297        makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]);
1298    }
1299
1300    // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear')
1301    makeGetterAndSetter('year', 'FullYear');
1302
1303    // add plural methods
1304    moment.fn.days = moment.fn.day;
1305    moment.fn.weeks = moment.fn.week;
1306    moment.fn.isoWeeks = moment.fn.isoWeek;
1307
1308    /************************************
1309        Duration Prototype
1310    ************************************/
1311
1312
1313    moment.duration.fn = Duration.prototype = {
1314        weeks : function () {
1315            return absRound(this.days() / 7);
1316        },
1317
1318        valueOf : function () {
1319            return this._milliseconds +
1320              this._days * 864e5 +
1321              this._months * 2592e6;
1322        },
1323
1324        humanize : function (withSuffix) {
1325            var difference = +this,
1326                output = relativeTime(difference, !withSuffix, this.lang());
1327
1328            if (withSuffix) {
1329                output = this.lang().pastFuture(difference, output);
1330            }
1331
1332            return this.lang().postformat(output);
1333        },
1334
1335        lang : moment.fn.lang
1336    };
1337
1338    function makeDurationGetter(name) {
1339        moment.duration.fn[name] = function () {
1340            return this._data[name];
1341        };
1342    }
1343
1344    function makeDurationAsGetter(name, factor) {
1345        moment.duration.fn['as' + name] = function () {
1346            return +this / factor;
1347        };
1348    }
1349
1350    for (i in unitMillisecondFactors) {
1351        if (unitMillisecondFactors.hasOwnProperty(i)) {
1352            makeDurationAsGetter(i, unitMillisecondFactors[i]);
1353            makeDurationGetter(i.toLowerCase());
1354        }
1355    }
1356
1357    makeDurationAsGetter('Weeks', 6048e5);
1358
1359
1360    /************************************
1361        Default Lang
1362    ************************************/
1363
1364
1365    // Set default language, other languages will inherit from English.
1366    moment.lang('en', {
1367        ordinal : function (number) {
1368            var b = number % 10,
1369                output = (~~ (number % 100 / 10) === 1) ? 'th' :
1370                (b === 1) ? 'st' :
1371                (b === 2) ? 'nd' :
1372                (b === 3) ? 'rd' : 'th';
1373            return number + output;
1374        }
1375    });
1376
1377
1378    /************************************
1379        Exposing Moment
1380    ************************************/
1381
1382
1383    // CommonJS module is defined
1384    if (hasModule) {
1385        module.exports = moment;
1386    }
1387    /*global ender:false */
1388    if (typeof ender === 'undefined') {
1389        // here, `this` means `window` in the browser, or `global` on the server
1390        // add `moment` as a global object via a string identifier,
1391        // for Closure Compiler "advanced" mode
1392        this['moment'] = moment;
1393    }
1394    /*global define:false */
1395    if (typeof define === "function" && define.amd) {
1396        define("moment", [], function () {
1397            return moment;
1398        });
1399    }
1400}).call(this);
Note: See TracBrowser for help on using the repository browser.