Merge "Don't use isset() to check for null"
[mediawiki.git] / resources / lib / moment / moment.js
blob83282c6fdbab67e9362c6e7f0421333f5a000090
1 //! moment.js
2 //! version : 2.7.0
3 //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
4 //! license : MIT
5 //! momentjs.com
7 (function (undefined) {
9     /************************************
10         Constants
11     ************************************/
13     var moment,
14         VERSION = "2.7.0",
15         // the global-scope this is NOT the global object in Node.js
16         globalScope = typeof global !== 'undefined' ? global : this,
17         oldGlobalMoment,
18         round = Math.round,
19         i,
21         YEAR = 0,
22         MONTH = 1,
23         DATE = 2,
24         HOUR = 3,
25         MINUTE = 4,
26         SECOND = 5,
27         MILLISECOND = 6,
29         // internal storage for language config files
30         languages = {},
32         // moment internal properties
33         momentProperties = {
34             _isAMomentObject: null,
35             _i : null,
36             _f : null,
37             _l : null,
38             _strict : null,
39             _tzm : null,
40             _isUTC : null,
41             _offset : null,  // optional. Combine with _isUTC
42             _pf : null,
43             _lang : null  // optional
44         },
46         // check for nodeJS
47         hasModule = (typeof module !== 'undefined' && module.exports),
49         // ASP.NET json date format regex
50         aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,
51         aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,
53         // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
54         // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
55         isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,
57         // format tokens
58         formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,
59         localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,
61         // parsing token regexes
62         parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
63         parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
64         parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999
65         parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
66         parseTokenDigits = /\d+/, // nonzero number of digits
67         parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic.
68         parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z
69         parseTokenT = /T/i, // T (ISO separator)
70         parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
71         parseTokenOrdinal = /\d{1,2}/,
73         //strict parsing regexes
74         parseTokenOneDigit = /\d/, // 0 - 9
75         parseTokenTwoDigits = /\d\d/, // 00 - 99
76         parseTokenThreeDigits = /\d{3}/, // 000 - 999
77         parseTokenFourDigits = /\d{4}/, // 0000 - 9999
78         parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999
79         parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf
81         // iso 8601 regex
82         // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
83         isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,
85         isoFormat = 'YYYY-MM-DDTHH:mm:ssZ',
87         isoDates = [
88             ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/],
89             ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/],
90             ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/],
91             ['GGGG-[W]WW', /\d{4}-W\d{2}/],
92             ['YYYY-DDD', /\d{4}-\d{3}/]
93         ],
95         // iso time formats and regexes
96         isoTimes = [
97             ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/],
98             ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/],
99             ['HH:mm', /(T| )\d\d:\d\d/],
100             ['HH', /(T| )\d\d/]
101         ],
103         // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"]
104         parseTimezoneChunker = /([\+\-]|\d\d)/gi,
106         // getter and setter names
107         proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'),
108         unitMillisecondFactors = {
109             'Milliseconds' : 1,
110             'Seconds' : 1e3,
111             'Minutes' : 6e4,
112             'Hours' : 36e5,
113             'Days' : 864e5,
114             'Months' : 2592e6,
115             'Years' : 31536e6
116         },
118         unitAliases = {
119             ms : 'millisecond',
120             s : 'second',
121             m : 'minute',
122             h : 'hour',
123             d : 'day',
124             D : 'date',
125             w : 'week',
126             W : 'isoWeek',
127             M : 'month',
128             Q : 'quarter',
129             y : 'year',
130             DDD : 'dayOfYear',
131             e : 'weekday',
132             E : 'isoWeekday',
133             gg: 'weekYear',
134             GG: 'isoWeekYear'
135         },
137         camelFunctions = {
138             dayofyear : 'dayOfYear',
139             isoweekday : 'isoWeekday',
140             isoweek : 'isoWeek',
141             weekyear : 'weekYear',
142             isoweekyear : 'isoWeekYear'
143         },
145         // format function strings
146         formatFunctions = {},
148         // default relative time thresholds
149         relativeTimeThresholds = {
150           s: 45,   //seconds to minutes
151           m: 45,   //minutes to hours
152           h: 22,   //hours to days
153           dd: 25,  //days to month (month == 1)
154           dm: 45,  //days to months (months > 1)
155           dy: 345  //days to year
156         },
158         // tokens to ordinalize and pad
159         ordinalizeTokens = 'DDD w W M D d'.split(' '),
160         paddedTokens = 'M D H h m s w W'.split(' '),
162         formatTokenFunctions = {
163             M    : function () {
164                 return this.month() + 1;
165             },
166             MMM  : function (format) {
167                 return this.lang().monthsShort(this, format);
168             },
169             MMMM : function (format) {
170                 return this.lang().months(this, format);
171             },
172             D    : function () {
173                 return this.date();
174             },
175             DDD  : function () {
176                 return this.dayOfYear();
177             },
178             d    : function () {
179                 return this.day();
180             },
181             dd   : function (format) {
182                 return this.lang().weekdaysMin(this, format);
183             },
184             ddd  : function (format) {
185                 return this.lang().weekdaysShort(this, format);
186             },
187             dddd : function (format) {
188                 return this.lang().weekdays(this, format);
189             },
190             w    : function () {
191                 return this.week();
192             },
193             W    : function () {
194                 return this.isoWeek();
195             },
196             YY   : function () {
197                 return leftZeroFill(this.year() % 100, 2);
198             },
199             YYYY : function () {
200                 return leftZeroFill(this.year(), 4);
201             },
202             YYYYY : function () {
203                 return leftZeroFill(this.year(), 5);
204             },
205             YYYYYY : function () {
206                 var y = this.year(), sign = y >= 0 ? '+' : '-';
207                 return sign + leftZeroFill(Math.abs(y), 6);
208             },
209             gg   : function () {
210                 return leftZeroFill(this.weekYear() % 100, 2);
211             },
212             gggg : function () {
213                 return leftZeroFill(this.weekYear(), 4);
214             },
215             ggggg : function () {
216                 return leftZeroFill(this.weekYear(), 5);
217             },
218             GG   : function () {
219                 return leftZeroFill(this.isoWeekYear() % 100, 2);
220             },
221             GGGG : function () {
222                 return leftZeroFill(this.isoWeekYear(), 4);
223             },
224             GGGGG : function () {
225                 return leftZeroFill(this.isoWeekYear(), 5);
226             },
227             e : function () {
228                 return this.weekday();
229             },
230             E : function () {
231                 return this.isoWeekday();
232             },
233             a    : function () {
234                 return this.lang().meridiem(this.hours(), this.minutes(), true);
235             },
236             A    : function () {
237                 return this.lang().meridiem(this.hours(), this.minutes(), false);
238             },
239             H    : function () {
240                 return this.hours();
241             },
242             h    : function () {
243                 return this.hours() % 12 || 12;
244             },
245             m    : function () {
246                 return this.minutes();
247             },
248             s    : function () {
249                 return this.seconds();
250             },
251             S    : function () {
252                 return toInt(this.milliseconds() / 100);
253             },
254             SS   : function () {
255                 return leftZeroFill(toInt(this.milliseconds() / 10), 2);
256             },
257             SSS  : function () {
258                 return leftZeroFill(this.milliseconds(), 3);
259             },
260             SSSS : function () {
261                 return leftZeroFill(this.milliseconds(), 3);
262             },
263             Z    : function () {
264                 var a = -this.zone(),
265                     b = "+";
266                 if (a < 0) {
267                     a = -a;
268                     b = "-";
269                 }
270                 return b + leftZeroFill(toInt(a / 60), 2) + ":" + leftZeroFill(toInt(a) % 60, 2);
271             },
272             ZZ   : function () {
273                 var a = -this.zone(),
274                     b = "+";
275                 if (a < 0) {
276                     a = -a;
277                     b = "-";
278                 }
279                 return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2);
280             },
281             z : function () {
282                 return this.zoneAbbr();
283             },
284             zz : function () {
285                 return this.zoneName();
286             },
287             X    : function () {
288                 return this.unix();
289             },
290             Q : function () {
291                 return this.quarter();
292             }
293         },
295         lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'];
297     // Pick the first defined of two or three arguments. dfl comes from
298     // default.
299     function dfl(a, b, c) {
300         switch (arguments.length) {
301             case 2: return a != null ? a : b;
302             case 3: return a != null ? a : b != null ? b : c;
303             default: throw new Error("Implement me");
304         }
305     }
307     function defaultParsingFlags() {
308         // We need to deep clone this object, and es5 standard is not very
309         // helpful.
310         return {
311             empty : false,
312             unusedTokens : [],
313             unusedInput : [],
314             overflow : -2,
315             charsLeftOver : 0,
316             nullInput : false,
317             invalidMonth : null,
318             invalidFormat : false,
319             userInvalidated : false,
320             iso: false
321         };
322     }
324     function deprecate(msg, fn) {
325         var firstTime = true;
326         function printMsg() {
327             if (moment.suppressDeprecationWarnings === false &&
328                     typeof console !== 'undefined' && console.warn) {
329                 console.warn("Deprecation warning: " + msg);
330             }
331         }
332         return extend(function () {
333             if (firstTime) {
334                 printMsg();
335                 firstTime = false;
336             }
337             return fn.apply(this, arguments);
338         }, fn);
339     }
341     function padToken(func, count) {
342         return function (a) {
343             return leftZeroFill(func.call(this, a), count);
344         };
345     }
346     function ordinalizeToken(func, period) {
347         return function (a) {
348             return this.lang().ordinal(func.call(this, a), period);
349         };
350     }
352     while (ordinalizeTokens.length) {
353         i = ordinalizeTokens.pop();
354         formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i);
355     }
356     while (paddedTokens.length) {
357         i = paddedTokens.pop();
358         formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2);
359     }
360     formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3);
363     /************************************
364         Constructors
365     ************************************/
367     function Language() {
369     }
371     // Moment prototype object
372     function Moment(config) {
373         checkOverflow(config);
374         extend(this, config);
375     }
377     // Duration Constructor
378     function Duration(duration) {
379         var normalizedInput = normalizeObjectUnits(duration),
380             years = normalizedInput.year || 0,
381             quarters = normalizedInput.quarter || 0,
382             months = normalizedInput.month || 0,
383             weeks = normalizedInput.week || 0,
384             days = normalizedInput.day || 0,
385             hours = normalizedInput.hour || 0,
386             minutes = normalizedInput.minute || 0,
387             seconds = normalizedInput.second || 0,
388             milliseconds = normalizedInput.millisecond || 0;
390         // representation for dateAddRemove
391         this._milliseconds = +milliseconds +
392             seconds * 1e3 + // 1000
393             minutes * 6e4 + // 1000 * 60
394             hours * 36e5; // 1000 * 60 * 60
395         // Because of dateAddRemove treats 24 hours as different from a
396         // day when working around DST, we need to store them separately
397         this._days = +days +
398             weeks * 7;
399         // It is impossible translate months into days without knowing
400         // which months you are are talking about, so we have to store
401         // it separately.
402         this._months = +months +
403             quarters * 3 +
404             years * 12;
406         this._data = {};
408         this._bubble();
409     }
411     /************************************
412         Helpers
413     ************************************/
416     function extend(a, b) {
417         for (var i in b) {
418             if (b.hasOwnProperty(i)) {
419                 a[i] = b[i];
420             }
421         }
423         if (b.hasOwnProperty("toString")) {
424             a.toString = b.toString;
425         }
427         if (b.hasOwnProperty("valueOf")) {
428             a.valueOf = b.valueOf;
429         }
431         return a;
432     }
434     function cloneMoment(m) {
435         var result = {}, i;
436         for (i in m) {
437             if (m.hasOwnProperty(i) && momentProperties.hasOwnProperty(i)) {
438                 result[i] = m[i];
439             }
440         }
442         return result;
443     }
445     function absRound(number) {
446         if (number < 0) {
447             return Math.ceil(number);
448         } else {
449             return Math.floor(number);
450         }
451     }
453     // left zero fill a number
454     // see http://jsperf.com/left-zero-filling for performance comparison
455     function leftZeroFill(number, targetLength, forceSign) {
456         var output = '' + Math.abs(number),
457             sign = number >= 0;
459         while (output.length < targetLength) {
460             output = '0' + output;
461         }
462         return (sign ? (forceSign ? '+' : '') : '-') + output;
463     }
465     // helper function for _.addTime and _.subtractTime
466     function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) {
467         var milliseconds = duration._milliseconds,
468             days = duration._days,
469             months = duration._months;
470         updateOffset = updateOffset == null ? true : updateOffset;
472         if (milliseconds) {
473             mom._d.setTime(+mom._d + milliseconds * isAdding);
474         }
475         if (days) {
476             rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding);
477         }
478         if (months) {
479             rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding);
480         }
481         if (updateOffset) {
482             moment.updateOffset(mom, days || months);
483         }
484     }
486     // check if is an array
487     function isArray(input) {
488         return Object.prototype.toString.call(input) === '[object Array]';
489     }
491     function isDate(input) {
492         return  Object.prototype.toString.call(input) === '[object Date]' ||
493                 input instanceof Date;
494     }
496     // compare two arrays, return the number of differences
497     function compareArrays(array1, array2, dontConvert) {
498         var len = Math.min(array1.length, array2.length),
499             lengthDiff = Math.abs(array1.length - array2.length),
500             diffs = 0,
501             i;
502         for (i = 0; i < len; i++) {
503             if ((dontConvert && array1[i] !== array2[i]) ||
504                 (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
505                 diffs++;
506             }
507         }
508         return diffs + lengthDiff;
509     }
511     function normalizeUnits(units) {
512         if (units) {
513             var lowered = units.toLowerCase().replace(/(.)s$/, '$1');
514             units = unitAliases[units] || camelFunctions[lowered] || lowered;
515         }
516         return units;
517     }
519     function normalizeObjectUnits(inputObject) {
520         var normalizedInput = {},
521             normalizedProp,
522             prop;
524         for (prop in inputObject) {
525             if (inputObject.hasOwnProperty(prop)) {
526                 normalizedProp = normalizeUnits(prop);
527                 if (normalizedProp) {
528                     normalizedInput[normalizedProp] = inputObject[prop];
529                 }
530             }
531         }
533         return normalizedInput;
534     }
536     function makeList(field) {
537         var count, setter;
539         if (field.indexOf('week') === 0) {
540             count = 7;
541             setter = 'day';
542         }
543         else if (field.indexOf('month') === 0) {
544             count = 12;
545             setter = 'month';
546         }
547         else {
548             return;
549         }
551         moment[field] = function (format, index) {
552             var i, getter,
553                 method = moment.fn._lang[field],
554                 results = [];
556             if (typeof format === 'number') {
557                 index = format;
558                 format = undefined;
559             }
561             getter = function (i) {
562                 var m = moment().utc().set(setter, i);
563                 return method.call(moment.fn._lang, m, format || '');
564             };
566             if (index != null) {
567                 return getter(index);
568             }
569             else {
570                 for (i = 0; i < count; i++) {
571                     results.push(getter(i));
572                 }
573                 return results;
574             }
575         };
576     }
578     function toInt(argumentForCoercion) {
579         var coercedNumber = +argumentForCoercion,
580             value = 0;
582         if (coercedNumber !== 0 && isFinite(coercedNumber)) {
583             if (coercedNumber >= 0) {
584                 value = Math.floor(coercedNumber);
585             } else {
586                 value = Math.ceil(coercedNumber);
587             }
588         }
590         return value;
591     }
593     function daysInMonth(year, month) {
594         return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
595     }
597     function weeksInYear(year, dow, doy) {
598         return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week;
599     }
601     function daysInYear(year) {
602         return isLeapYear(year) ? 366 : 365;
603     }
605     function isLeapYear(year) {
606         return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
607     }
609     function checkOverflow(m) {
610         var overflow;
611         if (m._a && m._pf.overflow === -2) {
612             overflow =
613                 m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH :
614                 m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE :
615                 m._a[HOUR] < 0 || m._a[HOUR] > 23 ? HOUR :
616                 m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE :
617                 m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND :
618                 m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND :
619                 -1;
621             if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
622                 overflow = DATE;
623             }
625             m._pf.overflow = overflow;
626         }
627     }
629     function isValid(m) {
630         if (m._isValid == null) {
631             m._isValid = !isNaN(m._d.getTime()) &&
632                 m._pf.overflow < 0 &&
633                 !m._pf.empty &&
634                 !m._pf.invalidMonth &&
635                 !m._pf.nullInput &&
636                 !m._pf.invalidFormat &&
637                 !m._pf.userInvalidated;
639             if (m._strict) {
640                 m._isValid = m._isValid &&
641                     m._pf.charsLeftOver === 0 &&
642                     m._pf.unusedTokens.length === 0;
643             }
644         }
645         return m._isValid;
646     }
648     function normalizeLanguage(key) {
649         return key ? key.toLowerCase().replace('_', '-') : key;
650     }
652     // Return a moment from input, that is local/utc/zone equivalent to model.
653     function makeAs(input, model) {
654         return model._isUTC ? moment(input).zone(model._offset || 0) :
655             moment(input).local();
656     }
658     /************************************
659         Languages
660     ************************************/
663     extend(Language.prototype, {
665         set : function (config) {
666             var prop, i;
667             for (i in config) {
668                 prop = config[i];
669                 if (typeof prop === 'function') {
670                     this[i] = prop;
671                 } else {
672                     this['_' + i] = prop;
673                 }
674             }
675         },
677         _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
678         months : function (m) {
679             return this._months[m.month()];
680         },
682         _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),
683         monthsShort : function (m) {
684             return this._monthsShort[m.month()];
685         },
687         monthsParse : function (monthName) {
688             var i, mom, regex;
690             if (!this._monthsParse) {
691                 this._monthsParse = [];
692             }
694             for (i = 0; i < 12; i++) {
695                 // make the regex if we don't have it already
696                 if (!this._monthsParse[i]) {
697                     mom = moment.utc([2000, i]);
698                     regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
699                     this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
700                 }
701                 // test the regex
702                 if (this._monthsParse[i].test(monthName)) {
703                     return i;
704                 }
705             }
706         },
708         _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
709         weekdays : function (m) {
710             return this._weekdays[m.day()];
711         },
713         _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),
714         weekdaysShort : function (m) {
715             return this._weekdaysShort[m.day()];
716         },
718         _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"),
719         weekdaysMin : function (m) {
720             return this._weekdaysMin[m.day()];
721         },
723         weekdaysParse : function (weekdayName) {
724             var i, mom, regex;
726             if (!this._weekdaysParse) {
727                 this._weekdaysParse = [];
728             }
730             for (i = 0; i < 7; i++) {
731                 // make the regex if we don't have it already
732                 if (!this._weekdaysParse[i]) {
733                     mom = moment([2000, 1]).day(i);
734                     regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
735                     this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
736                 }
737                 // test the regex
738                 if (this._weekdaysParse[i].test(weekdayName)) {
739                     return i;
740                 }
741             }
742         },
744         _longDateFormat : {
745             LT : "h:mm A",
746             L : "MM/DD/YYYY",
747             LL : "MMMM D YYYY",
748             LLL : "MMMM D YYYY LT",
749             LLLL : "dddd, MMMM D YYYY LT"
750         },
751         longDateFormat : function (key) {
752             var output = this._longDateFormat[key];
753             if (!output && this._longDateFormat[key.toUpperCase()]) {
754                 output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) {
755                     return val.slice(1);
756                 });
757                 this._longDateFormat[key] = output;
758             }
759             return output;
760         },
762         isPM : function (input) {
763             // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
764             // Using charAt should be more compatible.
765             return ((input + '').toLowerCase().charAt(0) === 'p');
766         },
768         _meridiemParse : /[ap]\.?m?\.?/i,
769         meridiem : function (hours, minutes, isLower) {
770             if (hours > 11) {
771                 return isLower ? 'pm' : 'PM';
772             } else {
773                 return isLower ? 'am' : 'AM';
774             }
775         },
777         _calendar : {
778             sameDay : '[Today at] LT',
779             nextDay : '[Tomorrow at] LT',
780             nextWeek : 'dddd [at] LT',
781             lastDay : '[Yesterday at] LT',
782             lastWeek : '[Last] dddd [at] LT',
783             sameElse : 'L'
784         },
785         calendar : function (key, mom) {
786             var output = this._calendar[key];
787             return typeof output === 'function' ? output.apply(mom) : output;
788         },
790         _relativeTime : {
791             future : "in %s",
792             past : "%s ago",
793             s : "a few seconds",
794             m : "a minute",
795             mm : "%d minutes",
796             h : "an hour",
797             hh : "%d hours",
798             d : "a day",
799             dd : "%d days",
800             M : "a month",
801             MM : "%d months",
802             y : "a year",
803             yy : "%d years"
804         },
805         relativeTime : function (number, withoutSuffix, string, isFuture) {
806             var output = this._relativeTime[string];
807             return (typeof output === 'function') ?
808                 output(number, withoutSuffix, string, isFuture) :
809                 output.replace(/%d/i, number);
810         },
811         pastFuture : function (diff, output) {
812             var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
813             return typeof format === 'function' ? format(output) : format.replace(/%s/i, output);
814         },
816         ordinal : function (number) {
817             return this._ordinal.replace("%d", number);
818         },
819         _ordinal : "%d",
821         preparse : function (string) {
822             return string;
823         },
825         postformat : function (string) {
826             return string;
827         },
829         week : function (mom) {
830             return weekOfYear(mom, this._week.dow, this._week.doy).week;
831         },
833         _week : {
834             dow : 0, // Sunday is the first day of the week.
835             doy : 6  // The week that contains Jan 1st is the first week of the year.
836         },
838         _invalidDate: 'Invalid date',
839         invalidDate: function () {
840             return this._invalidDate;
841         }
842     });
844     // Loads a language definition into the `languages` cache.  The function
845     // takes a key and optionally values.  If not in the browser and no values
846     // are provided, it will load the language file module.  As a convenience,
847     // this function also returns the language values.
848     function loadLang(key, values) {
849         values.abbr = key;
850         if (!languages[key]) {
851             languages[key] = new Language();
852         }
853         languages[key].set(values);
854         return languages[key];
855     }
857     // Remove a language from the `languages` cache. Mostly useful in tests.
858     function unloadLang(key) {
859         delete languages[key];
860     }
862     // Determines which language definition to use and returns it.
863     //
864     // With no parameters, it will return the global language.  If you
865     // pass in a language key, such as 'en', it will return the
866     // definition for 'en', so long as 'en' has already been loaded using
867     // moment.lang.
868     function getLangDefinition(key) {
869         var i = 0, j, lang, next, split,
870             get = function (k) {
871                 if (!languages[k] && hasModule) {
872                     try {
873                         require('./lang/' + k);
874                     } catch (e) { }
875                 }
876                 return languages[k];
877             };
879         if (!key) {
880             return moment.fn._lang;
881         }
883         if (!isArray(key)) {
884             //short-circuit everything else
885             lang = get(key);
886             if (lang) {
887                 return lang;
888             }
889             key = [key];
890         }
892         //pick the language from the array
893         //try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
894         //substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
895         while (i < key.length) {
896             split = normalizeLanguage(key[i]).split('-');
897             j = split.length;
898             next = normalizeLanguage(key[i + 1]);
899             next = next ? next.split('-') : null;
900             while (j > 0) {
901                 lang = get(split.slice(0, j).join('-'));
902                 if (lang) {
903                     return lang;
904                 }
905                 if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
906                     //the next array item is better than a shallower substring of this one
907                     break;
908                 }
909                 j--;
910             }
911             i++;
912         }
913         return moment.fn._lang;
914     }
916     /************************************
917         Formatting
918     ************************************/
921     function removeFormattingTokens(input) {
922         if (input.match(/\[[\s\S]/)) {
923             return input.replace(/^\[|\]$/g, "");
924         }
925         return input.replace(/\\/g, "");
926     }
928     function makeFormatFunction(format) {
929         var array = format.match(formattingTokens), i, length;
931         for (i = 0, length = array.length; i < length; i++) {
932             if (formatTokenFunctions[array[i]]) {
933                 array[i] = formatTokenFunctions[array[i]];
934             } else {
935                 array[i] = removeFormattingTokens(array[i]);
936             }
937         }
939         return function (mom) {
940             var output = "";
941             for (i = 0; i < length; i++) {
942                 output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];
943             }
944             return output;
945         };
946     }
948     // format date using native date object
949     function formatMoment(m, format) {
951         if (!m.isValid()) {
952             return m.lang().invalidDate();
953         }
955         format = expandFormat(format, m.lang());
957         if (!formatFunctions[format]) {
958             formatFunctions[format] = makeFormatFunction(format);
959         }
961         return formatFunctions[format](m);
962     }
964     function expandFormat(format, lang) {
965         var i = 5;
967         function replaceLongDateFormatTokens(input) {
968             return lang.longDateFormat(input) || input;
969         }
971         localFormattingTokens.lastIndex = 0;
972         while (i >= 0 && localFormattingTokens.test(format)) {
973             format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
974             localFormattingTokens.lastIndex = 0;
975             i -= 1;
976         }
978         return format;
979     }
982     /************************************
983         Parsing
984     ************************************/
987     // get the regex to find the next token
988     function getParseRegexForToken(token, config) {
989         var a, strict = config._strict;
990         switch (token) {
991         case 'Q':
992             return parseTokenOneDigit;
993         case 'DDDD':
994             return parseTokenThreeDigits;
995         case 'YYYY':
996         case 'GGGG':
997         case 'gggg':
998             return strict ? parseTokenFourDigits : parseTokenOneToFourDigits;
999         case 'Y':
1000         case 'G':
1001         case 'g':
1002             return parseTokenSignedNumber;
1003         case 'YYYYYY':
1004         case 'YYYYY':
1005         case 'GGGGG':
1006         case 'ggggg':
1007             return strict ? parseTokenSixDigits : parseTokenOneToSixDigits;
1008         case 'S':
1009             if (strict) { return parseTokenOneDigit; }
1010             /* falls through */
1011         case 'SS':
1012             if (strict) { return parseTokenTwoDigits; }
1013             /* falls through */
1014         case 'SSS':
1015             if (strict) { return parseTokenThreeDigits; }
1016             /* falls through */
1017         case 'DDD':
1018             return parseTokenOneToThreeDigits;
1019         case 'MMM':
1020         case 'MMMM':
1021         case 'dd':
1022         case 'ddd':
1023         case 'dddd':
1024             return parseTokenWord;
1025         case 'a':
1026         case 'A':
1027             return getLangDefinition(config._l)._meridiemParse;
1028         case 'X':
1029             return parseTokenTimestampMs;
1030         case 'Z':
1031         case 'ZZ':
1032             return parseTokenTimezone;
1033         case 'T':
1034             return parseTokenT;
1035         case 'SSSS':
1036             return parseTokenDigits;
1037         case 'MM':
1038         case 'DD':
1039         case 'YY':
1040         case 'GG':
1041         case 'gg':
1042         case 'HH':
1043         case 'hh':
1044         case 'mm':
1045         case 'ss':
1046         case 'ww':
1047         case 'WW':
1048             return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits;
1049         case 'M':
1050         case 'D':
1051         case 'd':
1052         case 'H':
1053         case 'h':
1054         case 'm':
1055         case 's':
1056         case 'w':
1057         case 'W':
1058         case 'e':
1059         case 'E':
1060             return parseTokenOneOrTwoDigits;
1061         case 'Do':
1062             return parseTokenOrdinal;
1063         default :
1064             a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), "i"));
1065             return a;
1066         }
1067     }
1069     function timezoneMinutesFromString(string) {
1070         string = string || "";
1071         var possibleTzMatches = (string.match(parseTokenTimezone) || []),
1072             tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [],
1073             parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0],
1074             minutes = +(parts[1] * 60) + toInt(parts[2]);
1076         return parts[0] === '+' ? -minutes : minutes;
1077     }
1079     // function to convert string input to date
1080     function addTimeToArrayFromToken(token, input, config) {
1081         var a, datePartArray = config._a;
1083         switch (token) {
1084         // QUARTER
1085         case 'Q':
1086             if (input != null) {
1087                 datePartArray[MONTH] = (toInt(input) - 1) * 3;
1088             }
1089             break;
1090         // MONTH
1091         case 'M' : // fall through to MM
1092         case 'MM' :
1093             if (input != null) {
1094                 datePartArray[MONTH] = toInt(input) - 1;
1095             }
1096             break;
1097         case 'MMM' : // fall through to MMMM
1098         case 'MMMM' :
1099             a = getLangDefinition(config._l).monthsParse(input);
1100             // if we didn't find a month name, mark the date as invalid.
1101             if (a != null) {
1102                 datePartArray[MONTH] = a;
1103             } else {
1104                 config._pf.invalidMonth = input;
1105             }
1106             break;
1107         // DAY OF MONTH
1108         case 'D' : // fall through to DD
1109         case 'DD' :
1110             if (input != null) {
1111                 datePartArray[DATE] = toInt(input);
1112             }
1113             break;
1114         case 'Do' :
1115             if (input != null) {
1116                 datePartArray[DATE] = toInt(parseInt(input, 10));
1117             }
1118             break;
1119         // DAY OF YEAR
1120         case 'DDD' : // fall through to DDDD
1121         case 'DDDD' :
1122             if (input != null) {
1123                 config._dayOfYear = toInt(input);
1124             }
1126             break;
1127         // YEAR
1128         case 'YY' :
1129             datePartArray[YEAR] = moment.parseTwoDigitYear(input);
1130             break;
1131         case 'YYYY' :
1132         case 'YYYYY' :
1133         case 'YYYYYY' :
1134             datePartArray[YEAR] = toInt(input);
1135             break;
1136         // AM / PM
1137         case 'a' : // fall through to A
1138         case 'A' :
1139             config._isPm = getLangDefinition(config._l).isPM(input);
1140             break;
1141         // 24 HOUR
1142         case 'H' : // fall through to hh
1143         case 'HH' : // fall through to hh
1144         case 'h' : // fall through to hh
1145         case 'hh' :
1146             datePartArray[HOUR] = toInt(input);
1147             break;
1148         // MINUTE
1149         case 'm' : // fall through to mm
1150         case 'mm' :
1151             datePartArray[MINUTE] = toInt(input);
1152             break;
1153         // SECOND
1154         case 's' : // fall through to ss
1155         case 'ss' :
1156             datePartArray[SECOND] = toInt(input);
1157             break;
1158         // MILLISECOND
1159         case 'S' :
1160         case 'SS' :
1161         case 'SSS' :
1162         case 'SSSS' :
1163             datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000);
1164             break;
1165         // UNIX TIMESTAMP WITH MS
1166         case 'X':
1167             config._d = new Date(parseFloat(input) * 1000);
1168             break;
1169         // TIMEZONE
1170         case 'Z' : // fall through to ZZ
1171         case 'ZZ' :
1172             config._useUTC = true;
1173             config._tzm = timezoneMinutesFromString(input);
1174             break;
1175         // WEEKDAY - human
1176         case 'dd':
1177         case 'ddd':
1178         case 'dddd':
1179             a = getLangDefinition(config._l).weekdaysParse(input);
1180             // if we didn't get a weekday name, mark the date as invalid
1181             if (a != null) {
1182                 config._w = config._w || {};
1183                 config._w['d'] = a;
1184             } else {
1185                 config._pf.invalidWeekday = input;
1186             }
1187             break;
1188         // WEEK, WEEK DAY - numeric
1189         case 'w':
1190         case 'ww':
1191         case 'W':
1192         case 'WW':
1193         case 'd':
1194         case 'e':
1195         case 'E':
1196             token = token.substr(0, 1);
1197             /* falls through */
1198         case 'gggg':
1199         case 'GGGG':
1200         case 'GGGGG':
1201             token = token.substr(0, 2);
1202             if (input) {
1203                 config._w = config._w || {};
1204                 config._w[token] = toInt(input);
1205             }
1206             break;
1207         case 'gg':
1208         case 'GG':
1209             config._w = config._w || {};
1210             config._w[token] = moment.parseTwoDigitYear(input);
1211         }
1212     }
1214     function dayOfYearFromWeekInfo(config) {
1215         var w, weekYear, week, weekday, dow, doy, temp, lang;
1217         w = config._w;
1218         if (w.GG != null || w.W != null || w.E != null) {
1219             dow = 1;
1220             doy = 4;
1222             // TODO: We need to take the current isoWeekYear, but that depends on
1223             // how we interpret now (local, utc, fixed offset). So create
1224             // a now version of current config (take local/utc/offset flags, and
1225             // create now).
1226             weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year);
1227             week = dfl(w.W, 1);
1228             weekday = dfl(w.E, 1);
1229         } else {
1230             lang = getLangDefinition(config._l);
1231             dow = lang._week.dow;
1232             doy = lang._week.doy;
1234             weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year);
1235             week = dfl(w.w, 1);
1237             if (w.d != null) {
1238                 // weekday -- low day numbers are considered next week
1239                 weekday = w.d;
1240                 if (weekday < dow) {
1241                     ++week;
1242                 }
1243             } else if (w.e != null) {
1244                 // local weekday -- counting starts from begining of week
1245                 weekday = w.e + dow;
1246             } else {
1247                 // default to begining of week
1248                 weekday = dow;
1249             }
1250         }
1251         temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow);
1253         config._a[YEAR] = temp.year;
1254         config._dayOfYear = temp.dayOfYear;
1255     }
1257     // convert an array to a date.
1258     // the array should mirror the parameters below
1259     // note: all values past the year are optional and will default to the lowest possible value.
1260     // [year, month, day , hour, minute, second, millisecond]
1261     function dateFromConfig(config) {
1262         var i, date, input = [], currentDate, yearToUse;
1264         if (config._d) {
1265             return;
1266         }
1268         currentDate = currentDateArray(config);
1270         //compute day of the year from weeks and weekdays
1271         if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
1272             dayOfYearFromWeekInfo(config);
1273         }
1275         //if the day of the year is set, figure out what it is
1276         if (config._dayOfYear) {
1277             yearToUse = dfl(config._a[YEAR], currentDate[YEAR]);
1279             if (config._dayOfYear > daysInYear(yearToUse)) {
1280                 config._pf._overflowDayOfYear = true;
1281             }
1283             date = makeUTCDate(yearToUse, 0, config._dayOfYear);
1284             config._a[MONTH] = date.getUTCMonth();
1285             config._a[DATE] = date.getUTCDate();
1286         }
1288         // Default to current date.
1289         // * if no year, month, day of month are given, default to today
1290         // * if day of month is given, default month and year
1291         // * if month is given, default only year
1292         // * if year is given, don't default anything
1293         for (i = 0; i < 3 && config._a[i] == null; ++i) {
1294             config._a[i] = input[i] = currentDate[i];
1295         }
1297         // Zero out whatever was not defaulted, including time
1298         for (; i < 7; i++) {
1299             config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
1300         }
1302         config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input);
1303         // Apply timezone offset from input. The actual zone can be changed
1304         // with parseZone.
1305         if (config._tzm != null) {
1306             config._d.setUTCMinutes(config._d.getUTCMinutes() + config._tzm);
1307         }
1308     }
1310     function dateFromObject(config) {
1311         var normalizedInput;
1313         if (config._d) {
1314             return;
1315         }
1317         normalizedInput = normalizeObjectUnits(config._i);
1318         config._a = [
1319             normalizedInput.year,
1320             normalizedInput.month,
1321             normalizedInput.day,
1322             normalizedInput.hour,
1323             normalizedInput.minute,
1324             normalizedInput.second,
1325             normalizedInput.millisecond
1326         ];
1328         dateFromConfig(config);
1329     }
1331     function currentDateArray(config) {
1332         var now = new Date();
1333         if (config._useUTC) {
1334             return [
1335                 now.getUTCFullYear(),
1336                 now.getUTCMonth(),
1337                 now.getUTCDate()
1338             ];
1339         } else {
1340             return [now.getFullYear(), now.getMonth(), now.getDate()];
1341         }
1342     }
1344     // date from string and format string
1345     function makeDateFromStringAndFormat(config) {
1347         if (config._f === moment.ISO_8601) {
1348             parseISO(config);
1349             return;
1350         }
1352         config._a = [];
1353         config._pf.empty = true;
1355         // This array is used to make a Date, either with `new Date` or `Date.UTC`
1356         var lang = getLangDefinition(config._l),
1357             string = '' + config._i,
1358             i, parsedInput, tokens, token, skipped,
1359             stringLength = string.length,
1360             totalParsedInputLength = 0;
1362         tokens = expandFormat(config._f, lang).match(formattingTokens) || [];
1364         for (i = 0; i < tokens.length; i++) {
1365             token = tokens[i];
1366             parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
1367             if (parsedInput) {
1368                 skipped = string.substr(0, string.indexOf(parsedInput));
1369                 if (skipped.length > 0) {
1370                     config._pf.unusedInput.push(skipped);
1371                 }
1372                 string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
1373                 totalParsedInputLength += parsedInput.length;
1374             }
1375             // don't parse if it's not a known token
1376             if (formatTokenFunctions[token]) {
1377                 if (parsedInput) {
1378                     config._pf.empty = false;
1379                 }
1380                 else {
1381                     config._pf.unusedTokens.push(token);
1382                 }
1383                 addTimeToArrayFromToken(token, parsedInput, config);
1384             }
1385             else if (config._strict && !parsedInput) {
1386                 config._pf.unusedTokens.push(token);
1387             }
1388         }
1390         // add remaining unparsed input length to the string
1391         config._pf.charsLeftOver = stringLength - totalParsedInputLength;
1392         if (string.length > 0) {
1393             config._pf.unusedInput.push(string);
1394         }
1396         // handle am pm
1397         if (config._isPm && config._a[HOUR] < 12) {
1398             config._a[HOUR] += 12;
1399         }
1400         // if is 12 am, change hours to 0
1401         if (config._isPm === false && config._a[HOUR] === 12) {
1402             config._a[HOUR] = 0;
1403         }
1405         dateFromConfig(config);
1406         checkOverflow(config);
1407     }
1409     function unescapeFormat(s) {
1410         return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
1411             return p1 || p2 || p3 || p4;
1412         });
1413     }
1415     // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
1416     function regexpEscape(s) {
1417         return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
1418     }
1420     // date from string and array of format strings
1421     function makeDateFromStringAndArray(config) {
1422         var tempConfig,
1423             bestMoment,
1425             scoreToBeat,
1426             i,
1427             currentScore;
1429         if (config._f.length === 0) {
1430             config._pf.invalidFormat = true;
1431             config._d = new Date(NaN);
1432             return;
1433         }
1435         for (i = 0; i < config._f.length; i++) {
1436             currentScore = 0;
1437             tempConfig = extend({}, config);
1438             tempConfig._pf = defaultParsingFlags();
1439             tempConfig._f = config._f[i];
1440             makeDateFromStringAndFormat(tempConfig);
1442             if (!isValid(tempConfig)) {
1443                 continue;
1444             }
1446             // if there is any input that was not parsed add a penalty for that format
1447             currentScore += tempConfig._pf.charsLeftOver;
1449             //or tokens
1450             currentScore += tempConfig._pf.unusedTokens.length * 10;
1452             tempConfig._pf.score = currentScore;
1454             if (scoreToBeat == null || currentScore < scoreToBeat) {
1455                 scoreToBeat = currentScore;
1456                 bestMoment = tempConfig;
1457             }
1458         }
1460         extend(config, bestMoment || tempConfig);
1461     }
1463     // date from iso format
1464     function parseISO(config) {
1465         var i, l,
1466             string = config._i,
1467             match = isoRegex.exec(string);
1469         if (match) {
1470             config._pf.iso = true;
1471             for (i = 0, l = isoDates.length; i < l; i++) {
1472                 if (isoDates[i][1].exec(string)) {
1473                     // match[5] should be "T" or undefined
1474                     config._f = isoDates[i][0] + (match[6] || " ");
1475                     break;
1476                 }
1477             }
1478             for (i = 0, l = isoTimes.length; i < l; i++) {
1479                 if (isoTimes[i][1].exec(string)) {
1480                     config._f += isoTimes[i][0];
1481                     break;
1482                 }
1483             }
1484             if (string.match(parseTokenTimezone)) {
1485                 config._f += "Z";
1486             }
1487             makeDateFromStringAndFormat(config);
1488         } else {
1489             config._isValid = false;
1490         }
1491     }
1493     // date from iso format or fallback
1494     function makeDateFromString(config) {
1495         parseISO(config);
1496         if (config._isValid === false) {
1497             delete config._isValid;
1498             moment.createFromInputFallback(config);
1499         }
1500     }
1502     function makeDateFromInput(config) {
1503         var input = config._i,
1504             matched = aspNetJsonRegex.exec(input);
1506         if (input === undefined) {
1507             config._d = new Date();
1508         } else if (matched) {
1509             config._d = new Date(+matched[1]);
1510         } else if (typeof input === 'string') {
1511             makeDateFromString(config);
1512         } else if (isArray(input)) {
1513             config._a = input.slice(0);
1514             dateFromConfig(config);
1515         } else if (isDate(input)) {
1516             config._d = new Date(+input);
1517         } else if (typeof(input) === 'object') {
1518             dateFromObject(config);
1519         } else if (typeof(input) === 'number') {
1520             // from milliseconds
1521             config._d = new Date(input);
1522         } else {
1523             moment.createFromInputFallback(config);
1524         }
1525     }
1527     function makeDate(y, m, d, h, M, s, ms) {
1528         //can't just apply() to create a date:
1529         //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
1530         var date = new Date(y, m, d, h, M, s, ms);
1532         //the date constructor doesn't accept years < 1970
1533         if (y < 1970) {
1534             date.setFullYear(y);
1535         }
1536         return date;
1537     }
1539     function makeUTCDate(y) {
1540         var date = new Date(Date.UTC.apply(null, arguments));
1541         if (y < 1970) {
1542             date.setUTCFullYear(y);
1543         }
1544         return date;
1545     }
1547     function parseWeekday(input, language) {
1548         if (typeof input === 'string') {
1549             if (!isNaN(input)) {
1550                 input = parseInt(input, 10);
1551             }
1552             else {
1553                 input = language.weekdaysParse(input);
1554                 if (typeof input !== 'number') {
1555                     return null;
1556                 }
1557             }
1558         }
1559         return input;
1560     }
1562     /************************************
1563         Relative Time
1564     ************************************/
1567     // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
1568     function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) {
1569         return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
1570     }
1572     function relativeTime(milliseconds, withoutSuffix, lang) {
1573         var seconds = round(Math.abs(milliseconds) / 1000),
1574             minutes = round(seconds / 60),
1575             hours = round(minutes / 60),
1576             days = round(hours / 24),
1577             years = round(days / 365),
1578             args = seconds < relativeTimeThresholds.s  && ['s', seconds] ||
1579                 minutes === 1 && ['m'] ||
1580                 minutes < relativeTimeThresholds.m && ['mm', minutes] ||
1581                 hours === 1 && ['h'] ||
1582                 hours < relativeTimeThresholds.h && ['hh', hours] ||
1583                 days === 1 && ['d'] ||
1584                 days <= relativeTimeThresholds.dd && ['dd', days] ||
1585                 days <= relativeTimeThresholds.dm && ['M'] ||
1586                 days < relativeTimeThresholds.dy && ['MM', round(days / 30)] ||
1587                 years === 1 && ['y'] || ['yy', years];
1588         args[2] = withoutSuffix;
1589         args[3] = milliseconds > 0;
1590         args[4] = lang;
1591         return substituteTimeAgo.apply({}, args);
1592     }
1595     /************************************
1596         Week of Year
1597     ************************************/
1600     // firstDayOfWeek       0 = sun, 6 = sat
1601     //                      the day of the week that starts the week
1602     //                      (usually sunday or monday)
1603     // firstDayOfWeekOfYear 0 = sun, 6 = sat
1604     //                      the first week is the week that contains the first
1605     //                      of this day of the week
1606     //                      (eg. ISO weeks use thursday (4))
1607     function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
1608         var end = firstDayOfWeekOfYear - firstDayOfWeek,
1609             daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(),
1610             adjustedMoment;
1613         if (daysToDayOfWeek > end) {
1614             daysToDayOfWeek -= 7;
1615         }
1617         if (daysToDayOfWeek < end - 7) {
1618             daysToDayOfWeek += 7;
1619         }
1621         adjustedMoment = moment(mom).add('d', daysToDayOfWeek);
1622         return {
1623             week: Math.ceil(adjustedMoment.dayOfYear() / 7),
1624             year: adjustedMoment.year()
1625         };
1626     }
1628     //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
1629     function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) {
1630         var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear;
1632         d = d === 0 ? 7 : d;
1633         weekday = weekday != null ? weekday : firstDayOfWeek;
1634         daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0);
1635         dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1;
1637         return {
1638             year: dayOfYear > 0 ? year : year - 1,
1639             dayOfYear: dayOfYear > 0 ?  dayOfYear : daysInYear(year - 1) + dayOfYear
1640         };
1641     }
1643     /************************************
1644         Top Level Functions
1645     ************************************/
1647     function makeMoment(config) {
1648         var input = config._i,
1649             format = config._f;
1651         if (input === null || (format === undefined && input === '')) {
1652             return moment.invalid({nullInput: true});
1653         }
1655         if (typeof input === 'string') {
1656             config._i = input = getLangDefinition().preparse(input);
1657         }
1659         if (moment.isMoment(input)) {
1660             config = cloneMoment(input);
1662             config._d = new Date(+input._d);
1663         } else if (format) {
1664             if (isArray(format)) {
1665                 makeDateFromStringAndArray(config);
1666             } else {
1667                 makeDateFromStringAndFormat(config);
1668             }
1669         } else {
1670             makeDateFromInput(config);
1671         }
1673         return new Moment(config);
1674     }
1676     moment = function (input, format, lang, strict) {
1677         var c;
1679         if (typeof(lang) === "boolean") {
1680             strict = lang;
1681             lang = undefined;
1682         }
1683         // object construction must be done this way.
1684         // https://github.com/moment/moment/issues/1423
1685         c = {};
1686         c._isAMomentObject = true;
1687         c._i = input;
1688         c._f = format;
1689         c._l = lang;
1690         c._strict = strict;
1691         c._isUTC = false;
1692         c._pf = defaultParsingFlags();
1694         return makeMoment(c);
1695     };
1697     moment.suppressDeprecationWarnings = false;
1699     moment.createFromInputFallback = deprecate(
1700             "moment construction falls back to js Date. This is " +
1701             "discouraged and will be removed in upcoming major " +
1702             "release. Please refer to " +
1703             "https://github.com/moment/moment/issues/1407 for more info.",
1704             function (config) {
1705         config._d = new Date(config._i);
1706     });
1708     // Pick a moment m from moments so that m[fn](other) is true for all
1709     // other. This relies on the function fn to be transitive.
1710     //
1711     // moments should either be an array of moment objects or an array, whose
1712     // first element is an array of moment objects.
1713     function pickBy(fn, moments) {
1714         var res, i;
1715         if (moments.length === 1 && isArray(moments[0])) {
1716             moments = moments[0];
1717         }
1718         if (!moments.length) {
1719             return moment();
1720         }
1721         res = moments[0];
1722         for (i = 1; i < moments.length; ++i) {
1723             if (moments[i][fn](res)) {
1724                 res = moments[i];
1725             }
1726         }
1727         return res;
1728     }
1730     moment.min = function () {
1731         var args = [].slice.call(arguments, 0);
1733         return pickBy('isBefore', args);
1734     };
1736     moment.max = function () {
1737         var args = [].slice.call(arguments, 0);
1739         return pickBy('isAfter', args);
1740     };
1742     // creating with utc
1743     moment.utc = function (input, format, lang, strict) {
1744         var c;
1746         if (typeof(lang) === "boolean") {
1747             strict = lang;
1748             lang = undefined;
1749         }
1750         // object construction must be done this way.
1751         // https://github.com/moment/moment/issues/1423
1752         c = {};
1753         c._isAMomentObject = true;
1754         c._useUTC = true;
1755         c._isUTC = true;
1756         c._l = lang;
1757         c._i = input;
1758         c._f = format;
1759         c._strict = strict;
1760         c._pf = defaultParsingFlags();
1762         return makeMoment(c).utc();
1763     };
1765     // creating with unix timestamp (in seconds)
1766     moment.unix = function (input) {
1767         return moment(input * 1000);
1768     };
1770     // duration
1771     moment.duration = function (input, key) {
1772         var duration = input,
1773             // matching against regexp is expensive, do it on demand
1774             match = null,
1775             sign,
1776             ret,
1777             parseIso;
1779         if (moment.isDuration(input)) {
1780             duration = {
1781                 ms: input._milliseconds,
1782                 d: input._days,
1783                 M: input._months
1784             };
1785         } else if (typeof input === 'number') {
1786             duration = {};
1787             if (key) {
1788                 duration[key] = input;
1789             } else {
1790                 duration.milliseconds = input;
1791             }
1792         } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) {
1793             sign = (match[1] === "-") ? -1 : 1;
1794             duration = {
1795                 y: 0,
1796                 d: toInt(match[DATE]) * sign,
1797                 h: toInt(match[HOUR]) * sign,
1798                 m: toInt(match[MINUTE]) * sign,
1799                 s: toInt(match[SECOND]) * sign,
1800                 ms: toInt(match[MILLISECOND]) * sign
1801             };
1802         } else if (!!(match = isoDurationRegex.exec(input))) {
1803             sign = (match[1] === "-") ? -1 : 1;
1804             parseIso = function (inp) {
1805                 // We'd normally use ~~inp for this, but unfortunately it also
1806                 // converts floats to ints.
1807                 // inp may be undefined, so careful calling replace on it.
1808                 var res = inp && parseFloat(inp.replace(',', '.'));
1809                 // apply sign while we're at it
1810                 return (isNaN(res) ? 0 : res) * sign;
1811             };
1812             duration = {
1813                 y: parseIso(match[2]),
1814                 M: parseIso(match[3]),
1815                 d: parseIso(match[4]),
1816                 h: parseIso(match[5]),
1817                 m: parseIso(match[6]),
1818                 s: parseIso(match[7]),
1819                 w: parseIso(match[8])
1820             };
1821         }
1823         ret = new Duration(duration);
1825         if (moment.isDuration(input) && input.hasOwnProperty('_lang')) {
1826             ret._lang = input._lang;
1827         }
1829         return ret;
1830     };
1832     // version number
1833     moment.version = VERSION;
1835     // default format
1836     moment.defaultFormat = isoFormat;
1838     // constant that refers to the ISO standard
1839     moment.ISO_8601 = function () {};
1841     // Plugins that add properties should also add the key here (null value),
1842     // so we can properly clone ourselves.
1843     moment.momentProperties = momentProperties;
1845     // This function will be called whenever a moment is mutated.
1846     // It is intended to keep the offset in sync with the timezone.
1847     moment.updateOffset = function () {};
1849     // This function allows you to set a threshold for relative time strings
1850     moment.relativeTimeThreshold = function(threshold, limit) {
1851       if (relativeTimeThresholds[threshold] === undefined) {
1852         return false;
1853       }
1854       relativeTimeThresholds[threshold] = limit;
1855       return true;
1856     };
1858     // This function will load languages and then set the global language.  If
1859     // no arguments are passed in, it will simply return the current global
1860     // language key.
1861     moment.lang = function (key, values) {
1862         var r;
1863         if (!key) {
1864             return moment.fn._lang._abbr;
1865         }
1866         if (values) {
1867             loadLang(normalizeLanguage(key), values);
1868         } else if (values === null) {
1869             unloadLang(key);
1870             key = 'en';
1871         } else if (!languages[key]) {
1872             getLangDefinition(key);
1873         }
1874         r = moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key);
1875         return r._abbr;
1876     };
1878     // returns language data
1879     moment.langData = function (key) {
1880         if (key && key._lang && key._lang._abbr) {
1881             key = key._lang._abbr;
1882         }
1883         return getLangDefinition(key);
1884     };
1886     // compare moment object
1887     moment.isMoment = function (obj) {
1888         return obj instanceof Moment ||
1889             (obj != null &&  obj.hasOwnProperty('_isAMomentObject'));
1890     };
1892     // for typechecking Duration objects
1893     moment.isDuration = function (obj) {
1894         return obj instanceof Duration;
1895     };
1897     for (i = lists.length - 1; i >= 0; --i) {
1898         makeList(lists[i]);
1899     }
1901     moment.normalizeUnits = function (units) {
1902         return normalizeUnits(units);
1903     };
1905     moment.invalid = function (flags) {
1906         var m = moment.utc(NaN);
1907         if (flags != null) {
1908             extend(m._pf, flags);
1909         }
1910         else {
1911             m._pf.userInvalidated = true;
1912         }
1914         return m;
1915     };
1917     moment.parseZone = function () {
1918         return moment.apply(null, arguments).parseZone();
1919     };
1921     moment.parseTwoDigitYear = function (input) {
1922         return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
1923     };
1925     /************************************
1926         Moment Prototype
1927     ************************************/
1930     extend(moment.fn = Moment.prototype, {
1932         clone : function () {
1933             return moment(this);
1934         },
1936         valueOf : function () {
1937             return +this._d + ((this._offset || 0) * 60000);
1938         },
1940         unix : function () {
1941             return Math.floor(+this / 1000);
1942         },
1944         toString : function () {
1945             return this.clone().lang('en').format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ");
1946         },
1948         toDate : function () {
1949             return this._offset ? new Date(+this) : this._d;
1950         },
1952         toISOString : function () {
1953             var m = moment(this).utc();
1954             if (0 < m.year() && m.year() <= 9999) {
1955                 return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
1956             } else {
1957                 return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
1958             }
1959         },
1961         toArray : function () {
1962             var m = this;
1963             return [
1964                 m.year(),
1965                 m.month(),
1966                 m.date(),
1967                 m.hours(),
1968                 m.minutes(),
1969                 m.seconds(),
1970                 m.milliseconds()
1971             ];
1972         },
1974         isValid : function () {
1975             return isValid(this);
1976         },
1978         isDSTShifted : function () {
1980             if (this._a) {
1981                 return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0;
1982             }
1984             return false;
1985         },
1987         parsingFlags : function () {
1988             return extend({}, this._pf);
1989         },
1991         invalidAt: function () {
1992             return this._pf.overflow;
1993         },
1995         utc : function () {
1996             return this.zone(0);
1997         },
1999         local : function () {
2000             this.zone(0);
2001             this._isUTC = false;
2002             return this;
2003         },
2005         format : function (inputString) {
2006             var output = formatMoment(this, inputString || moment.defaultFormat);
2007             return this.lang().postformat(output);
2008         },
2010         add : function (input, val) {
2011             var dur;
2012             // switch args to support add('s', 1) and add(1, 's')
2013             if (typeof input === 'string' && typeof val === 'string') {
2014                 dur = moment.duration(isNaN(+val) ? +input : +val, isNaN(+val) ? val : input);
2015             } else if (typeof input === 'string') {
2016                 dur = moment.duration(+val, input);
2017             } else {
2018                 dur = moment.duration(input, val);
2019             }
2020             addOrSubtractDurationFromMoment(this, dur, 1);
2021             return this;
2022         },
2024         subtract : function (input, val) {
2025             var dur;
2026             // switch args to support subtract('s', 1) and subtract(1, 's')
2027             if (typeof input === 'string' && typeof val === 'string') {
2028                 dur = moment.duration(isNaN(+val) ? +input : +val, isNaN(+val) ? val : input);
2029             } else if (typeof input === 'string') {
2030                 dur = moment.duration(+val, input);
2031             } else {
2032                 dur = moment.duration(input, val);
2033             }
2034             addOrSubtractDurationFromMoment(this, dur, -1);
2035             return this;
2036         },
2038         diff : function (input, units, asFloat) {
2039             var that = makeAs(input, this),
2040                 zoneDiff = (this.zone() - that.zone()) * 6e4,
2041                 diff, output;
2043             units = normalizeUnits(units);
2045             if (units === 'year' || units === 'month') {
2046                 // average number of days in the months in the given dates
2047                 diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2
2048                 // difference in months
2049                 output = ((this.year() - that.year()) * 12) + (this.month() - that.month());
2050                 // adjust by taking difference in days, average number of days
2051                 // and dst in the given months.
2052                 output += ((this - moment(this).startOf('month')) -
2053                         (that - moment(that).startOf('month'))) / diff;
2054                 // same as above but with zones, to negate all dst
2055                 output -= ((this.zone() - moment(this).startOf('month').zone()) -
2056                         (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff;
2057                 if (units === 'year') {
2058                     output = output / 12;
2059                 }
2060             } else {
2061                 diff = (this - that);
2062                 output = units === 'second' ? diff / 1e3 : // 1000
2063                     units === 'minute' ? diff / 6e4 : // 1000 * 60
2064                     units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60
2065                     units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
2066                     units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
2067                     diff;
2068             }
2069             return asFloat ? output : absRound(output);
2070         },
2072         from : function (time, withoutSuffix) {
2073             return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix);
2074         },
2076         fromNow : function (withoutSuffix) {
2077             return this.from(moment(), withoutSuffix);
2078         },
2080         calendar : function (time) {
2081             // We want to compare the start of today, vs this.
2082             // Getting start-of-today depends on whether we're zone'd or not.
2083             var now = time || moment(),
2084                 sod = makeAs(now, this).startOf('day'),
2085                 diff = this.diff(sod, 'days', true),
2086                 format = diff < -6 ? 'sameElse' :
2087                     diff < -1 ? 'lastWeek' :
2088                     diff < 0 ? 'lastDay' :
2089                     diff < 1 ? 'sameDay' :
2090                     diff < 2 ? 'nextDay' :
2091                     diff < 7 ? 'nextWeek' : 'sameElse';
2092             return this.format(this.lang().calendar(format, this));
2093         },
2095         isLeapYear : function () {
2096             return isLeapYear(this.year());
2097         },
2099         isDST : function () {
2100             return (this.zone() < this.clone().month(0).zone() ||
2101                 this.zone() < this.clone().month(5).zone());
2102         },
2104         day : function (input) {
2105             var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
2106             if (input != null) {
2107                 input = parseWeekday(input, this.lang());
2108                 return this.add({ d : input - day });
2109             } else {
2110                 return day;
2111             }
2112         },
2114         month : makeAccessor('Month', true),
2116         startOf: function (units) {
2117             units = normalizeUnits(units);
2118             // the following switch intentionally omits break keywords
2119             // to utilize falling through the cases.
2120             switch (units) {
2121             case 'year':
2122                 this.month(0);
2123                 /* falls through */
2124             case 'quarter':
2125             case 'month':
2126                 this.date(1);
2127                 /* falls through */
2128             case 'week':
2129             case 'isoWeek':
2130             case 'day':
2131                 this.hours(0);
2132                 /* falls through */
2133             case 'hour':
2134                 this.minutes(0);
2135                 /* falls through */
2136             case 'minute':
2137                 this.seconds(0);
2138                 /* falls through */
2139             case 'second':
2140                 this.milliseconds(0);
2141                 /* falls through */
2142             }
2144             // weeks are a special case
2145             if (units === 'week') {
2146                 this.weekday(0);
2147             } else if (units === 'isoWeek') {
2148                 this.isoWeekday(1);
2149             }
2151             // quarters are also special
2152             if (units === 'quarter') {
2153                 this.month(Math.floor(this.month() / 3) * 3);
2154             }
2156             return this;
2157         },
2159         endOf: function (units) {
2160             units = normalizeUnits(units);
2161             return this.startOf(units).add((units === 'isoWeek' ? 'week' : units), 1).subtract('ms', 1);
2162         },
2164         isAfter: function (input, units) {
2165             units = typeof units !== 'undefined' ? units : 'millisecond';
2166             return +this.clone().startOf(units) > +moment(input).startOf(units);
2167         },
2169         isBefore: function (input, units) {
2170             units = typeof units !== 'undefined' ? units : 'millisecond';
2171             return +this.clone().startOf(units) < +moment(input).startOf(units);
2172         },
2174         isSame: function (input, units) {
2175             units = units || 'ms';
2176             return +this.clone().startOf(units) === +makeAs(input, this).startOf(units);
2177         },
2179         min: deprecate(
2180                  "moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",
2181                  function (other) {
2182                      other = moment.apply(null, arguments);
2183                      return other < this ? this : other;
2184                  }
2185          ),
2187         max: deprecate(
2188                 "moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",
2189                 function (other) {
2190                     other = moment.apply(null, arguments);
2191                     return other > this ? this : other;
2192                 }
2193         ),
2195         // keepTime = true means only change the timezone, without affecting
2196         // the local hour. So 5:31:26 +0300 --[zone(2, true)]--> 5:31:26 +0200
2197         // It is possible that 5:31:26 doesn't exist int zone +0200, so we
2198         // adjust the time as needed, to be valid.
2199         //
2200         // Keeping the time actually adds/subtracts (one hour)
2201         // from the actual represented time. That is why we call updateOffset
2202         // a second time. In case it wants us to change the offset again
2203         // _changeInProgress == true case, then we have to adjust, because
2204         // there is no such time in the given timezone.
2205         zone : function (input, keepTime) {
2206             var offset = this._offset || 0;
2207             if (input != null) {
2208                 if (typeof input === "string") {
2209                     input = timezoneMinutesFromString(input);
2210                 }
2211                 if (Math.abs(input) < 16) {
2212                     input = input * 60;
2213                 }
2214                 this._offset = input;
2215                 this._isUTC = true;
2216                 if (offset !== input) {
2217                     if (!keepTime || this._changeInProgress) {
2218                         addOrSubtractDurationFromMoment(this,
2219                                 moment.duration(offset - input, 'm'), 1, false);
2220                     } else if (!this._changeInProgress) {
2221                         this._changeInProgress = true;
2222                         moment.updateOffset(this, true);
2223                         this._changeInProgress = null;
2224                     }
2225                 }
2226             } else {
2227                 return this._isUTC ? offset : this._d.getTimezoneOffset();
2228             }
2229             return this;
2230         },
2232         zoneAbbr : function () {
2233             return this._isUTC ? "UTC" : "";
2234         },
2236         zoneName : function () {
2237             return this._isUTC ? "Coordinated Universal Time" : "";
2238         },
2240         parseZone : function () {
2241             if (this._tzm) {
2242                 this.zone(this._tzm);
2243             } else if (typeof this._i === 'string') {
2244                 this.zone(this._i);
2245             }
2246             return this;
2247         },
2249         hasAlignedHourOffset : function (input) {
2250             if (!input) {
2251                 input = 0;
2252             }
2253             else {
2254                 input = moment(input).zone();
2255             }
2257             return (this.zone() - input) % 60 === 0;
2258         },
2260         daysInMonth : function () {
2261             return daysInMonth(this.year(), this.month());
2262         },
2264         dayOfYear : function (input) {
2265             var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1;
2266             return input == null ? dayOfYear : this.add("d", (input - dayOfYear));
2267         },
2269         quarter : function (input) {
2270             return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
2271         },
2273         weekYear : function (input) {
2274             var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year;
2275             return input == null ? year : this.add("y", (input - year));
2276         },
2278         isoWeekYear : function (input) {
2279             var year = weekOfYear(this, 1, 4).year;
2280             return input == null ? year : this.add("y", (input - year));
2281         },
2283         week : function (input) {
2284             var week = this.lang().week(this);
2285             return input == null ? week : this.add("d", (input - week) * 7);
2286         },
2288         isoWeek : function (input) {
2289             var week = weekOfYear(this, 1, 4).week;
2290             return input == null ? week : this.add("d", (input - week) * 7);
2291         },
2293         weekday : function (input) {
2294             var weekday = (this.day() + 7 - this.lang()._week.dow) % 7;
2295             return input == null ? weekday : this.add("d", input - weekday);
2296         },
2298         isoWeekday : function (input) {
2299             // behaves the same as moment#day except
2300             // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
2301             // as a setter, sunday should belong to the previous week.
2302             return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7);
2303         },
2305         isoWeeksInYear : function () {
2306             return weeksInYear(this.year(), 1, 4);
2307         },
2309         weeksInYear : function () {
2310             var weekInfo = this._lang._week;
2311             return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
2312         },
2314         get : function (units) {
2315             units = normalizeUnits(units);
2316             return this[units]();
2317         },
2319         set : function (units, value) {
2320             units = normalizeUnits(units);
2321             if (typeof this[units] === 'function') {
2322                 this[units](value);
2323             }
2324             return this;
2325         },
2327         // If passed a language key, it will set the language for this
2328         // instance.  Otherwise, it will return the language configuration
2329         // variables for this instance.
2330         lang : function (key) {
2331             if (key === undefined) {
2332                 return this._lang;
2333             } else {
2334                 this._lang = getLangDefinition(key);
2335                 return this;
2336             }
2337         }
2338     });
2340     function rawMonthSetter(mom, value) {
2341         var dayOfMonth;
2343         // TODO: Move this out of here!
2344         if (typeof value === 'string') {
2345             value = mom.lang().monthsParse(value);
2346             // TODO: Another silent failure?
2347             if (typeof value !== 'number') {
2348                 return mom;
2349             }
2350         }
2352         dayOfMonth = Math.min(mom.date(),
2353                 daysInMonth(mom.year(), value));
2354         mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
2355         return mom;
2356     }
2358     function rawGetter(mom, unit) {
2359         return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]();
2360     }
2362     function rawSetter(mom, unit, value) {
2363         if (unit === 'Month') {
2364             return rawMonthSetter(mom, value);
2365         } else {
2366             return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
2367         }
2368     }
2370     function makeAccessor(unit, keepTime) {
2371         return function (value) {
2372             if (value != null) {
2373                 rawSetter(this, unit, value);
2374                 moment.updateOffset(this, keepTime);
2375                 return this;
2376             } else {
2377                 return rawGetter(this, unit);
2378             }
2379         };
2380     }
2382     moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false);
2383     moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false);
2384     moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false);
2385     // Setting the hour should keep the time, because the user explicitly
2386     // specified which hour he wants. So trying to maintain the same hour (in
2387     // a new timezone) makes sense. Adding/subtracting hours does not follow
2388     // this rule.
2389     moment.fn.hour = moment.fn.hours = makeAccessor('Hours', true);
2390     // moment.fn.month is defined separately
2391     moment.fn.date = makeAccessor('Date', true);
2392     moment.fn.dates = deprecate("dates accessor is deprecated. Use date instead.", makeAccessor('Date', true));
2393     moment.fn.year = makeAccessor('FullYear', true);
2394     moment.fn.years = deprecate("years accessor is deprecated. Use year instead.", makeAccessor('FullYear', true));
2396     // add plural methods
2397     moment.fn.days = moment.fn.day;
2398     moment.fn.months = moment.fn.month;
2399     moment.fn.weeks = moment.fn.week;
2400     moment.fn.isoWeeks = moment.fn.isoWeek;
2401     moment.fn.quarters = moment.fn.quarter;
2403     // add aliased format methods
2404     moment.fn.toJSON = moment.fn.toISOString;
2406     /************************************
2407         Duration Prototype
2408     ************************************/
2411     extend(moment.duration.fn = Duration.prototype, {
2413         _bubble : function () {
2414             var milliseconds = this._milliseconds,
2415                 days = this._days,
2416                 months = this._months,
2417                 data = this._data,
2418                 seconds, minutes, hours, years;
2420             // The following code bubbles up values, see the tests for
2421             // examples of what that means.
2422             data.milliseconds = milliseconds % 1000;
2424             seconds = absRound(milliseconds / 1000);
2425             data.seconds = seconds % 60;
2427             minutes = absRound(seconds / 60);
2428             data.minutes = minutes % 60;
2430             hours = absRound(minutes / 60);
2431             data.hours = hours % 24;
2433             days += absRound(hours / 24);
2434             data.days = days % 30;
2436             months += absRound(days / 30);
2437             data.months = months % 12;
2439             years = absRound(months / 12);
2440             data.years = years;
2441         },
2443         weeks : function () {
2444             return absRound(this.days() / 7);
2445         },
2447         valueOf : function () {
2448             return this._milliseconds +
2449               this._days * 864e5 +
2450               (this._months % 12) * 2592e6 +
2451               toInt(this._months / 12) * 31536e6;
2452         },
2454         humanize : function (withSuffix) {
2455             var difference = +this,
2456                 output = relativeTime(difference, !withSuffix, this.lang());
2458             if (withSuffix) {
2459                 output = this.lang().pastFuture(difference, output);
2460             }
2462             return this.lang().postformat(output);
2463         },
2465         add : function (input, val) {
2466             // supports only 2.0-style add(1, 's') or add(moment)
2467             var dur = moment.duration(input, val);
2469             this._milliseconds += dur._milliseconds;
2470             this._days += dur._days;
2471             this._months += dur._months;
2473             this._bubble();
2475             return this;
2476         },
2478         subtract : function (input, val) {
2479             var dur = moment.duration(input, val);
2481             this._milliseconds -= dur._milliseconds;
2482             this._days -= dur._days;
2483             this._months -= dur._months;
2485             this._bubble();
2487             return this;
2488         },
2490         get : function (units) {
2491             units = normalizeUnits(units);
2492             return this[units.toLowerCase() + 's']();
2493         },
2495         as : function (units) {
2496             units = normalizeUnits(units);
2497             return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's']();
2498         },
2500         lang : moment.fn.lang,
2502         toIsoString : function () {
2503             // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
2504             var years = Math.abs(this.years()),
2505                 months = Math.abs(this.months()),
2506                 days = Math.abs(this.days()),
2507                 hours = Math.abs(this.hours()),
2508                 minutes = Math.abs(this.minutes()),
2509                 seconds = Math.abs(this.seconds() + this.milliseconds() / 1000);
2511             if (!this.asSeconds()) {
2512                 // this is the same as C#'s (Noda) and python (isodate)...
2513                 // but not other JS (goog.date)
2514                 return 'P0D';
2515             }
2517             return (this.asSeconds() < 0 ? '-' : '') +
2518                 'P' +
2519                 (years ? years + 'Y' : '') +
2520                 (months ? months + 'M' : '') +
2521                 (days ? days + 'D' : '') +
2522                 ((hours || minutes || seconds) ? 'T' : '') +
2523                 (hours ? hours + 'H' : '') +
2524                 (minutes ? minutes + 'M' : '') +
2525                 (seconds ? seconds + 'S' : '');
2526         }
2527     });
2529     function makeDurationGetter(name) {
2530         moment.duration.fn[name] = function () {
2531             return this._data[name];
2532         };
2533     }
2535     function makeDurationAsGetter(name, factor) {
2536         moment.duration.fn['as' + name] = function () {
2537             return +this / factor;
2538         };
2539     }
2541     for (i in unitMillisecondFactors) {
2542         if (unitMillisecondFactors.hasOwnProperty(i)) {
2543             makeDurationAsGetter(i, unitMillisecondFactors[i]);
2544             makeDurationGetter(i.toLowerCase());
2545         }
2546     }
2548     makeDurationAsGetter('Weeks', 6048e5);
2549     moment.duration.fn.asMonths = function () {
2550         return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12;
2551     };
2554     /************************************
2555         Default Lang
2556     ************************************/
2559     // Set default language, other languages will inherit from English.
2560     moment.lang('en', {
2561         ordinal : function (number) {
2562             var b = number % 10,
2563                 output = (toInt(number % 100 / 10) === 1) ? 'th' :
2564                 (b === 1) ? 'st' :
2565                 (b === 2) ? 'nd' :
2566                 (b === 3) ? 'rd' : 'th';
2567             return number + output;
2568         }
2569     });
2571     /* EMBED_LANGUAGES */
2573     /************************************
2574         Exposing Moment
2575     ************************************/
2577     function makeGlobal(shouldDeprecate) {
2578         /*global ender:false */
2579         if (typeof ender !== 'undefined') {
2580             return;
2581         }
2582         oldGlobalMoment = globalScope.moment;
2583         if (shouldDeprecate) {
2584             globalScope.moment = deprecate(
2585                     "Accessing Moment through the global scope is " +
2586                     "deprecated, and will be removed in an upcoming " +
2587                     "release.",
2588                     moment);
2589         } else {
2590             globalScope.moment = moment;
2591         }
2592     }
2594     // CommonJS module is defined
2595     if (hasModule) {
2596         module.exports = moment;
2597     } else if (typeof define === "function" && define.amd) {
2598         define("moment", function (require, exports, module) {
2599             if (module.config && module.config() && module.config().noGlobal === true) {
2600                 // release the global variable
2601                 globalScope.moment = oldGlobalMoment;
2602             }
2604             return moment;
2605         });
2606         makeGlobal(true);
2607     } else {
2608         makeGlobal();
2609     }
2610 }).call(this);