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