History

GSF.Web: Updated moment.js to reference the latest build to remove any known security vunerabilities.

Billy Ernest committed 8 years ago

Commit c94ec7e1 parent be1fbac2 files · +3947 −2454Browse files

Showing the changes to Source/Libraries/GSF.Web/Shared/Scripts (1 of 2 files). Show all

Unified · Split

Source/Libraries/GSF.Web/Shared/Scripts/moment.js+3946−2453
@@ -1,538 +1,232 @@
1//! moment.js1//! moment.js
2//! version : 2.9.02//! version : 2.20.1
3//! authors : Tim Wood, Iskren Chernev, Moment.js contributors3//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
4//! license : MIT4//! license : MIT
5//! momentjs.com5//! momentjs.com
6 6
7(function (undefined) {7; (function (global, factory) {
8 /************************************8 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
9 Constants9 typeof define === 'function' && define.amd ? define(factory) :
10 ************************************/10 global.moment = factory()
11 11}(this, (function () {
12 var moment,12 'use strict';
13 VERSION = '2.9.0',
14 // the global-scope this is NOT the global object in Node.js
15 globalScope = (typeof global !== 'undefined' && (typeof window === 'undefined' || window === global.window)) ? global : this,
16 oldGlobalMoment,
17 round = Math.round,
18 hasOwnProperty = Object.prototype.hasOwnProperty,
19 i,
20
21 YEAR = 0,
22 MONTH = 1,
23 DATE = 2,
24 HOUR = 3,
25 MINUTE = 4,
26 SECOND = 5,
27 MILLISECOND = 6,
28
29 // internal storage for locale config files
30 locales = {},
31
32 // extra moment internal properties (plugins register props here)
33 momentProperties = [],
34
35 // check for nodeJS
36 hasModule = (typeof module !== 'undefined' && module && module.exports),
37
38 // ASP.NET json date format regex
39 aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,
40 aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,
41
42 // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
43 // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
44 isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,
45
46 // format tokens
47 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|X|zz?|ZZ?|.)/g,
48 localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,
49
50 // parsing token regexes
51 parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
52 parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
53 parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999
54 parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
55 parseTokenDigits = /\d+/, // nonzero number of digits
56 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.
57 parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z
58 parseTokenT = /T/i, // T (ISO separator)
59 parseTokenOffsetMs = /[\+\-]?\d+/, // 1234567890123
60 parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
61
62 //strict parsing regexes
63 parseTokenOneDigit = /\d/, // 0 - 9
64 parseTokenTwoDigits = /\d\d/, // 00 - 99
65 parseTokenThreeDigits = /\d{3}/, // 000 - 999
66 parseTokenFourDigits = /\d{4}/, // 0000 - 9999
67 parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999
68 parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf
69
70 // iso 8601 regex
71 // 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)
72 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)?)?$/,
73
74 isoFormat = 'YYYY-MM-DDTHH:mm:ssZ',
75
76 isoDates = [
77 ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/],
78 ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/],
79 ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/],
80 ['GGGG-[W]WW', /\d{4}-W\d{2}/],
81 ['YYYY-DDD', /\d{4}-\d{3}/]
82 ],
83
84 // iso time formats and regexes
85 isoTimes = [
86 ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/],
87 ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/],
88 ['HH:mm', /(T| )\d\d:\d\d/],
89 ['HH', /(T| )\d\d/]
90 ],
91
92 // timezone chunker '+10:00' > ['10', '00'] or '-1530' > ['-', '15', '30']
93 parseTimezoneChunker = /([\+\-]|\d\d)/gi,
94
95 // getter and setter names
96 proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'),
97 unitMillisecondFactors = {
98 'Milliseconds' : 1,
99 'Seconds' : 1e3,
100 'Minutes' : 6e4,
101 'Hours' : 36e5,
102 'Days' : 864e5,
103 'Months' : 2592e6,
104 'Years' : 31536e6
105 },
106
107 unitAliases = {
108 ms : 'millisecond',
109 s : 'second',
110 m : 'minute',
111 h : 'hour',
112 d : 'day',
113 D : 'date',
114 w : 'week',
115 W : 'isoWeek',
116 M : 'month',
117 Q : 'quarter',
118 y : 'year',
119 DDD : 'dayOfYear',
120 e : 'weekday',
121 E : 'isoWeekday',
122 gg: 'weekYear',
123 GG: 'isoWeekYear'
124 },
125
126 camelFunctions = {
127 dayofyear : 'dayOfYear',
128 isoweekday : 'isoWeekday',
129 isoweek : 'isoWeek',
130 weekyear : 'weekYear',
131 isoweekyear : 'isoWeekYear'
132 },
133
134 // format function strings
135 formatFunctions = {},
136
137 // default relative time thresholds
138 relativeTimeThresholds = {
139 s: 45, // seconds to minute
140 m: 45, // minutes to hour
141 h: 22, // hours to day
142 d: 26, // days to month
143 M: 11 // months to year
144 },
145
146 // tokens to ordinalize and pad
147 ordinalizeTokens = 'DDD w W M D d'.split(' '),
148 paddedTokens = 'M D H h m s w W'.split(' '),
149
150 formatTokenFunctions = {
151 M : function () {
152 return this.month() + 1;
153 },
154 MMM : function (format) {
155 return this.localeData().monthsShort(this, format);
156 },
157 MMMM : function (format) {
158 return this.localeData().months(this, format);
159 },
160 D : function () {
161 return this.date();
162 },
163 DDD : function () {
164 return this.dayOfYear();
165 },
166 d : function () {
167 return this.day();
168 },
169 dd : function (format) {
170 return this.localeData().weekdaysMin(this, format);
171 },
172 ddd : function (format) {
173 return this.localeData().weekdaysShort(this, format);
174 },
175 dddd : function (format) {
176 return this.localeData().weekdays(this, format);
177 },
178 w : function () {
179 return this.week();
180 },
181 W : function () {
182 return this.isoWeek();
183 },
184 YY : function () {
185 return leftZeroFill(this.year() % 100, 2);
186 },
187 YYYY : function () {
188 return leftZeroFill(this.year(), 4);
189 },
190 YYYYY : function () {
191 return leftZeroFill(this.year(), 5);
192 },
193 YYYYYY : function () {
194 var y = this.year(), sign = y >= 0 ? '+' : '-';
195 return sign + leftZeroFill(Math.abs(y), 6);
196 },
197 gg : function () {
198 return leftZeroFill(this.weekYear() % 100, 2);
199 },
200 gggg : function () {
201 return leftZeroFill(this.weekYear(), 4);
202 },
203 ggggg : function () {
204 return leftZeroFill(this.weekYear(), 5);
205 },
206 GG : function () {
207 return leftZeroFill(this.isoWeekYear() % 100, 2);
208 },
209 GGGG : function () {
210 return leftZeroFill(this.isoWeekYear(), 4);
211 },
212 GGGGG : function () {
213 return leftZeroFill(this.isoWeekYear(), 5);
214 },
215 e : function () {
216 return this.weekday();
217 },
218 E : function () {
219 return this.isoWeekday();
220 },
221 a : function () {
222 return this.localeData().meridiem(this.hours(), this.minutes(), true);
223 },
224 A : function () {
225 return this.localeData().meridiem(this.hours(), this.minutes(), false);
226 },
227 H : function () {
228 return this.hours();
229 },
230 h : function () {
231 return this.hours() % 12 || 12;
232 },
233 m : function () {
234 return this.minutes();
235 },
236 s : function () {
237 return this.seconds();
238 },
239 S : function () {
240 return toInt(this.milliseconds() / 100);
241 },
242 SS : function () {
243 return leftZeroFill(toInt(this.milliseconds() / 10), 2);
244 },
245 SSS : function () {
246 return leftZeroFill(this.milliseconds(), 3);
247 },
248 SSSS : function () {
249 return leftZeroFill(this.milliseconds(), 3);
250 },
251 Z : function () {
252 var a = this.utcOffset(),
253 b = '+';
254 if (a < 0) {
255 a = -a;
256 b = '-';
257 }
258 return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2);
259 },
260 ZZ : function () {
261 var a = this.utcOffset(),
262 b = '+';
263 if (a < 0) {
264 a = -a;
265 b = '-';
266 }
267 return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2);
268 },
269 z : function () {
270 return this.zoneAbbr();
271 },
272 zz : function () {
273 return this.zoneName();
274 },
275 x : function () {
276 return this.valueOf();
277 },
278 X : function () {
279 return this.unix();
280 },
281 Q : function () {
282 return this.quarter();
283 }
284 },
285
286 deprecations = {},
287 13
288 lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'],14 var hookCallback;
289 15
290 updateInProgress = false;16 function hooks() {
291 17 return hookCallback.apply(null, arguments);
292 // Pick the first defined of two or three arguments. dfl comes from
293 // default.
294 function dfl(a, b, c) {
295 switch (arguments.length) {
296 case 2: return a != null ? a : b;
297 case 3: return a != null ? a : b != null ? b : c;
298 default: throw new Error('Implement me');
299 }
300 }18 }
301 19
302 function hasOwnProp(a, b) {20 // This is done to register the method called with moment()
303 return hasOwnProperty.call(a, b);21 // without creating circular dependencies.
22 function setHookCallback(callback) {
23 hookCallback = callback;
304 }24 }
305 25
306 function defaultParsingFlags() {26 function isArray(input) {
307 // We need to deep clone this object, and es5 standard is not very27 return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
308 // helpful.
309 return {
310 empty : false,
311 unusedTokens : [],
312 unusedInput : [],
313 overflow : -2,
314 charsLeftOver : 0,
315 nullInput : false,
316 invalidMonth : null,
317 invalidFormat : false,
318 userInvalidated : false,
319 iso: false
320 };
321 }28 }
322 29
323 function printMsg(msg) {30 function isObject(input) {
324 if (moment.suppressDeprecationWarnings === false &&31 // IE8 will treat undefined and null as object if it wasn't for
325 typeof console !== 'undefined' && console.warn) {32 // input != null
326 console.warn('Deprecation warning: ' + msg);33 return input != null && Object.prototype.toString.call(input) === '[object Object]';
327 }
328 }34 }
329 35
330 function deprecate(msg, fn) {36 function isObjectEmpty(obj) {
331 var firstTime = true;37 if (Object.getOwnPropertyNames) {
332 return extend(function () {38 return (Object.getOwnPropertyNames(obj).length === 0);
333 if (firstTime) {39 } else {
334 printMsg(msg);40 var k;
335 firstTime = false;41 for (k in obj) {
42 if (obj.hasOwnProperty(k)) {
43 return false;
44 }
336 }45 }
337 return fn.apply(this, arguments);46 return true;
338 }, fn);
339 }
340
341 function deprecateSimple(name, msg) {
342 if (!deprecations[name]) {
343 printMsg(msg);
344 deprecations[name] = true;
345 }47 }
346 }48 }
347 49
348 function padToken(func, count) {50 function isUndefined(input) {
349 return function (a) {51 return input === void 0;
350 return leftZeroFill(func.call(this, a), count);
351 };
352 }52 }
353 function ordinalizeToken(func, period) {53
354 return function (a) {54 function isNumber(input) {
355 return this.localeData().ordinal(func.call(this, a), period);55 return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
356 };
357 }56 }
358 57
359 function monthDiff(a, b) {58 function isDate(input) {
360 // difference in months59 return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
361 var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),60 }
362 // b is in (anchor - 1 month, anchor + 1 month)
363 anchor = a.clone().add(wholeMonthDiff, 'months'),
364 anchor2, adjust;
365 61
366 if (b - anchor < 0) {62 function map(arr, fn) {
367 anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');63 var res = [], i;
368 // linear across the month64 for (i = 0; i < arr.length; ++i) {
369 adjust = (b - anchor) / (anchor - anchor2);65 res.push(fn(arr[i], i));
370 } else {
371 anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
372 // linear across the month
373 adjust = (b - anchor) / (anchor2 - anchor);
374 }66 }
375 67 return res;
376 return -(wholeMonthDiff + adjust);
377 }68 }
378 69
379 while (ordinalizeTokens.length) {70 function hasOwnProp(a, b) {
380 i = ordinalizeTokens.pop();71 return Object.prototype.hasOwnProperty.call(a, b);
381 formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i);
382 }
383 while (paddedTokens.length) {
384 i = paddedTokens.pop();
385 formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2);
386 }72 }
387 formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3);
388 73
74 function extend(a, b) {
75 for (var i in b) {
76 if (hasOwnProp(b, i)) {
77 a[i] = b[i];
78 }
79 }
389 80
390 function meridiemFixWrap(locale, hour, meridiem) {81 if (hasOwnProp(b, 'toString')) {
391 var isPm;82 a.toString = b.toString;
392
393 if (meridiem == null) {
394 // nothing to do
395 return hour;
396 }83 }
397 if (locale.meridiemHour != null) {84
398 return locale.meridiemHour(hour, meridiem);85 if (hasOwnProp(b, 'valueOf')) {
399 } else if (locale.isPM != null) {86 a.valueOf = b.valueOf;
400 // Fallback
401 isPm = locale.isPM(meridiem);
402 if (isPm && hour < 12) {
403 hour += 12;
404 }
405 if (!isPm && hour === 12) {
406 hour = 0;
407 }
408 return hour;
409 } else {
410 // thie is not supposed to happen
411 return hour;
412 }87 }
88
89 return a;
413 }90 }
414 91
415 /************************************92 function createUTC(input, format, locale, strict) {
416 Constructors93 return createLocalOrUTC(input, format, locale, strict, true).utc();
417 ************************************/94 }
418 95
419 function Locale() {96 function defaultParsingFlags() {
97 // We need to deep clone this object.
98 return {
99 empty: false,
100 unusedTokens: [],
101 unusedInput: [],
102 overflow: -2,
103 charsLeftOver: 0,
104 nullInput: false,
105 invalidMonth: null,
106 invalidFormat: false,
107 userInvalidated: false,
108 iso: false,
109 parsedDateParts: [],
110 meridiem: null,
111 rfc2822: false,
112 weekdayMismatch: false
113 };
420 }114 }
421 115
422 // Moment prototype object116 function getParsingFlags(m) {
423 function Moment(config, skipOverflow) {117 if (m._pf == null) {
424 if (skipOverflow !== false) {118 m._pf = defaultParsingFlags();
425 checkOverflow(config);
426 }
427 copyConfig(this, config);
428 this._d = new Date(+config._d);
429 // Prevent infinite loop in case updateOffset creates new moment
430 // objects.
431 if (updateInProgress === false) {
432 updateInProgress = true;
433 moment.updateOffset(this);
434 updateInProgress = false;
435 }119 }
120 return m._pf;
436 }121 }
437 122
438 // Duration Constructor123 var some;
439 function Duration(duration) {124 if (Array.prototype.some) {
440 var normalizedInput = normalizeObjectUnits(duration),125 some = Array.prototype.some;
441 years = normalizedInput.year || 0,126 } else {
442 quarters = normalizedInput.quarter || 0,127 some = function (fun) {
443 months = normalizedInput.month || 0,128 var t = Object(this);
444 weeks = normalizedInput.week || 0,129 var len = t.length >>> 0;
445 days = normalizedInput.day || 0,
446 hours = normalizedInput.hour || 0,
447 minutes = normalizedInput.minute || 0,
448 seconds = normalizedInput.second || 0,
449 milliseconds = normalizedInput.millisecond || 0;
450
451 // representation for dateAddRemove
452 this._milliseconds = +milliseconds +
453 seconds * 1e3 + // 1000
454 minutes * 6e4 + // 1000 * 60
455 hours * 36e5; // 1000 * 60 * 60
456 // Because of dateAddRemove treats 24 hours as different from a
457 // day when working around DST, we need to store them separately
458 this._days = +days +
459 weeks * 7;
460 // It is impossible translate months into days without knowing
461 // which months you are are talking about, so we have to store
462 // it separately.
463 this._months = +months +
464 quarters * 3 +
465 years * 12;
466
467 this._data = {};
468 130
469 this._locale = moment.localeData();131 for (var i = 0; i < len; i++) {
132 if (i in t && fun.call(this, t[i], i, t)) {
133 return true;
134 }
135 }
470 136
471 this._bubble();137 return false;
138 };
472 }139 }
473 140
474 /************************************141 function isValid(m) {
475 Helpers142 if (m._isValid == null) {
476 ************************************/143 var flags = getParsingFlags(m);
144 var parsedParts = some.call(flags.parsedDateParts, function (i) {
145 return i != null;
146 });
147 var isNowValid = !isNaN(m._d.getTime()) &&
148 flags.overflow < 0 &&
149 !flags.empty &&
150 !flags.invalidMonth &&
151 !flags.invalidWeekday &&
152 !flags.weekdayMismatch &&
153 !flags.nullInput &&
154 !flags.invalidFormat &&
155 !flags.userInvalidated &&
156 (!flags.meridiem || (flags.meridiem && parsedParts));
477 157
158 if (m._strict) {
159 isNowValid = isNowValid &&
160 flags.charsLeftOver === 0 &&
161 flags.unusedTokens.length === 0 &&
162 flags.bigHour === undefined;
163 }
478 164
479 function extend(a, b) {165 if (Object.isFrozen == null || !Object.isFrozen(m)) {
480 for (var i in b) {166 m._isValid = isNowValid;
481 if (hasOwnProp(b, i)) {167 }
482 a[i] = b[i];168 else {
169 return isNowValid;
483 }170 }
484 }171 }
172 return m._isValid;
173 }
485 174
486 if (hasOwnProp(b, 'toString')) {175 function createInvalid(flags) {
487 a.toString = b.toString;176 var m = createUTC(NaN);
177 if (flags != null) {
178 extend(getParsingFlags(m), flags);
488 }179 }
489 180 else {
490 if (hasOwnProp(b, 'valueOf')) {181 getParsingFlags(m).userInvalidated = true;
491 a.valueOf = b.valueOf;
492 }182 }
493 183
494 return a;184 return m;
495 }185 }
496 186
187 // Plugins that add properties should also add the key here (null value),
188 // so we can properly clone ourselves.
189 var momentProperties = hooks.momentProperties = [];
190
497 function copyConfig(to, from) {191 function copyConfig(to, from) {
498 var i, prop, val;192 var i, prop, val;
499 193
500 if (typeof from._isAMomentObject !== 'undefined') {194 if (!isUndefined(from._isAMomentObject)) {
501 to._isAMomentObject = from._isAMomentObject;195 to._isAMomentObject = from._isAMomentObject;
502 }196 }
503 if (typeof from._i !== 'undefined') {197 if (!isUndefined(from._i)) {
504 to._i = from._i;198 to._i = from._i;
505 }199 }
506 if (typeof from._f !== 'undefined') {200 if (!isUndefined(from._f)) {
507 to._f = from._f;201 to._f = from._f;
508 }202 }
509 if (typeof from._l !== 'undefined') {203 if (!isUndefined(from._l)) {
510 to._l = from._l;204 to._l = from._l;
511 }205 }
512 if (typeof from._strict !== 'undefined') {206 if (!isUndefined(from._strict)) {
513 to._strict = from._strict;207 to._strict = from._strict;
514 }208 }
515 if (typeof from._tzm !== 'undefined') {209 if (!isUndefined(from._tzm)) {
516 to._tzm = from._tzm;210 to._tzm = from._tzm;
517 }211 }
518 if (typeof from._isUTC !== 'undefined') {212 if (!isUndefined(from._isUTC)) {
519 to._isUTC = from._isUTC;213 to._isUTC = from._isUTC;
520 }214 }
521 if (typeof from._offset !== 'undefined') {215 if (!isUndefined(from._offset)) {
522 to._offset = from._offset;216 to._offset = from._offset;
523 }217 }
524 if (typeof from._pf !== 'undefined') {218 if (!isUndefined(from._pf)) {
525 to._pf = from._pf;219 to._pf = getParsingFlags(from);
526 }220 }
527 if (typeof from._locale !== 'undefined') {221 if (!isUndefined(from._locale)) {
528 to._locale = from._locale;222 to._locale = from._locale;
529 }223 }
530 224
531 if (momentProperties.length > 0) {225 if (momentProperties.length > 0) {
532 for (i in momentProperties) {226 for (i = 0; i < momentProperties.length; i++) {
533 prop = momentProperties[i];227 prop = momentProperties[i];
534 val = from[prop];228 val = from[prop];
535 if (typeof val !== 'undefined') {229 if (!isUndefined(val)) {
536 to[prop] = val;230 to[prop] = val;
537 }231 }
538 }232 }
@@ -541,99 +235,46 @@ · 2 unmodified lines
541 return to;235 return to;
542 }236 }
543 237
544 function absRound(number) {238 var updateInProgress = false;
545 if (number < 0) {
546 return Math.ceil(number);
547 } else {
548 return Math.floor(number);
549 }
550 }
551
552 // left zero fill a number
553 // see http://jsperf.com/left-zero-filling for performance comparison
554 function leftZeroFill(number, targetLength, forceSign) {
555 var output = '' + Math.abs(number),
556 sign = number >= 0;
557 239
558 while (output.length < targetLength) {240 // Moment prototype object
559 output = '0' + output;241 function Moment(config) {
242 copyConfig(this, config);
243 this._d = new Date(config._d != null ? config._d.getTime() : NaN);
244 if (!this.isValid()) {
245 this._d = new Date(NaN);
560 }246 }
561 return (sign ? (forceSign ? '+' : '') : '-') + output;247 // Prevent infinite loop in case updateOffset creates new moment
562 }248 // objects.
563 249 if (updateInProgress === false) {
564 function positiveMomentsDifference(base, other) {250 updateInProgress = true;
565 var res = {milliseconds: 0, months: 0};251 hooks.updateOffset(this);
566 252 updateInProgress = false;
567 res.months = other.month() - base.month() +
568 (other.year() - base.year()) * 12;
569 if (base.clone().add(res.months, 'M').isAfter(other)) {
570 --res.months;
571 }253 }
254 }
572 255
573 res.milliseconds = +other - +(base.clone().add(res.months, 'M'));256 function isMoment(obj) {
574 257 return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
575 return res;
576 }258 }
577 259
578 function momentsDifference(base, other) {260 function absFloor(number) {
579 var res;261 if (number < 0) {
580 other = makeAs(other, base);262 // -0 -> 0
581 if (base.isBefore(other)) {263 return Math.ceil(number) || 0;
582 res = positiveMomentsDifference(base, other);
583 } else {264 } else {
584 res = positiveMomentsDifference(other, base);265 return Math.floor(number);
585 res.milliseconds = -res.milliseconds;
586 res.months = -res.months;
587 }266 }
588
589 return res;
590 }
591
592 // TODO: remove 'name' arg after deprecation is removed
593 function createAdder(direction, name) {
594 return function (val, period) {
595 var dur, tmp;
596 //invert the arguments, but complain about it
597 if (period !== null && !isNaN(+period)) {
598 deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).');
599 tmp = val; val = period; period = tmp;
600 }
601
602 val = typeof val === 'string' ? +val : val;
603 dur = moment.duration(val, period);
604 addOrSubtractDurationFromMoment(this, dur, direction);
605 return this;
606 };
607 }267 }
608 268
609 function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) {269 function toInt(argumentForCoercion) {
610 var milliseconds = duration._milliseconds,270 var coercedNumber = +argumentForCoercion,
611 days = duration._days,271 value = 0;
612 months = duration._months;
613 updateOffset = updateOffset == null ? true : updateOffset;
614 272
615 if (milliseconds) {273 if (coercedNumber !== 0 && isFinite(coercedNumber)) {
616 mom._d.setTime(+mom._d + milliseconds * isAdding);274 value = absFloor(coercedNumber);
617 }
618 if (days) {
619 rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding);
620 }
621 if (months) {
622 rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding);
623 }
624 if (updateOffset) {
625 moment.updateOffset(mom, days || months);
626 }275 }
627 }
628 276
629 // check if is an array277 return value;
630 function isArray(input) {
631 return Object.prototype.toString.call(input) === '[object Array]';
632 }
633
634 function isDate(input) {
635 return Object.prototype.toString.call(input) === '[object Date]' ||
636 input instanceof Date;
637 }278 }
638 279
639 // compare two arrays, return the number of differences280 // compare two arrays, return the number of differences
@@ -651,424 +292,295 @@ · 11 unmodified lines
651 return diffs + lengthDiff;292 return diffs + lengthDiff;
652 }293 }
653 294
654 function normalizeUnits(units) {295 function warn(msg) {
655 if (units) {296 if (hooks.suppressDeprecationWarnings === false &&
656 var lowered = units.toLowerCase().replace(/(.)s$/, '$1');297 (typeof console !== 'undefined') && console.warn) {
657 units = unitAliases[units] || camelFunctions[lowered] || lowered;298 console.warn('Deprecation warning: ' + msg);
658 }299 }
659 return units;
660 }300 }
661 301
662 function normalizeObjectUnits(inputObject) {302 function deprecate(msg, fn) {
663 var normalizedInput = {},303 var firstTime = true;
664 normalizedProp,
665 prop;
666 304
667 for (prop in inputObject) {305 return extend(function () {
668 if (hasOwnProp(inputObject, prop)) {306 if (hooks.deprecationHandler != null) {
669 normalizedProp = normalizeUnits(prop);307 hooks.deprecationHandler(null, msg);
670 if (normalizedProp) {308 }
671 normalizedInput[normalizedProp] = inputObject[prop];309 if (firstTime) {
310 var args = [];
311 var arg;
312 for (var i = 0; i < arguments.length; i++) {
313 arg = '';
314 if (typeof arguments[i] === 'object') {
315 arg += '\n[' + i + '] ';
316 for (var key in arguments[0]) {
317 arg += key + ': ' + arguments[0][key] + ', ';
318 }
319 arg = arg.slice(0, -2); // Remove trailing comma and space
320 } else {
321 arg = arguments[i];
322 }
323 args.push(arg);
672 }324 }
325 warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack);
326 firstTime = false;
673 }327 }
674 }328 return fn.apply(this, arguments);
675 329 }, fn);
676 return normalizedInput;
677 }330 }
678 331
679 function makeList(field) {332 var deprecations = {};
680 var count, setter;
681 333
682 if (field.indexOf('week') === 0) {334 function deprecateSimple(name, msg) {
683 count = 7;335 if (hooks.deprecationHandler != null) {
684 setter = 'day';336 hooks.deprecationHandler(name, msg);
685 }337 }
686 else if (field.indexOf('month') === 0) {338 if (!deprecations[name]) {
687 count = 12;339 warn(msg);
688 setter = 'month';340 deprecations[name] = true;
689 }
690 else {
691 return;
692 }341 }
342 }
693 343
694 moment[field] = function (format, index) {344 hooks.suppressDeprecationWarnings = false;
695 var i, getter,345 hooks.deprecationHandler = null;
696 method = moment._locale[field],
697 results = [];
698
699 if (typeof format === 'number') {
700 index = format;
701 format = undefined;
702 }
703
704 getter = function (i) {
705 var m = moment().utc().set(setter, i);
706 return method.call(moment._locale, m, format || '');
707 };
708 346
709 if (index != null) {347 function isFunction(input) {
710 return getter(index);348 return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
711 }
712 else {
713 for (i = 0; i < count; i++) {
714 results.push(getter(i));
715 }
716 return results;
717 }
718 };
719 }349 }
720 350
721 function toInt(argumentForCoercion) {351 function set(config) {
722 var coercedNumber = +argumentForCoercion,352 var prop, i;
723 value = 0;353 for (i in config) {
724 354 prop = config[i];
725 if (coercedNumber !== 0 && isFinite(coercedNumber)) {355 if (isFunction(prop)) {
726 if (coercedNumber >= 0) {356 this[i] = prop;
727 value = Math.floor(coercedNumber);
728 } else {357 } else {
729 value = Math.ceil(coercedNumber);358 this['_' + i] = prop;
730 }359 }
731 }360 }
732 361 this._config = config;
733 return value;362 // Lenient ordinal parsing accepts just a number in addition to
363 // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
364 // TODO: Remove "ordinalParse" fallback in next major release.
365 this._dayOfMonthOrdinalParseLenient = new RegExp(
366 (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) +
367 '|' + (/\d{1,2}/).source);
734 }368 }
735 369
736 function daysInMonth(year, month) {370 function mergeConfigs(parentConfig, childConfig) {
737 return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();371 var res = extend({}, parentConfig), prop;
372 for (prop in childConfig) {
373 if (hasOwnProp(childConfig, prop)) {
374 if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
375 res[prop] = {};
376 extend(res[prop], parentConfig[prop]);
377 extend(res[prop], childConfig[prop]);
378 } else if (childConfig[prop] != null) {
379 res[prop] = childConfig[prop];
380 } else {
381 delete res[prop];
382 }
383 }
384 }
385 for (prop in parentConfig) {
386 if (hasOwnProp(parentConfig, prop) &&
387 !hasOwnProp(childConfig, prop) &&
388 isObject(parentConfig[prop])) {
389 // make sure changes to properties don't modify parent config
390 res[prop] = extend({}, res[prop]);
391 }
392 }
393 return res;
738 }394 }
739 395
740 function weeksInYear(year, dow, doy) {396 function Locale(config) {
741 return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week;397 if (config != null) {
398 this.set(config);
399 }
742 }400 }
743 401
744 function daysInYear(year) {402 var keys;
745 return isLeapYear(year) ? 366 : 365;403
404 if (Object.keys) {
405 keys = Object.keys;
406 } else {
407 keys = function (obj) {
408 var i, res = [];
409 for (i in obj) {
410 if (hasOwnProp(obj, i)) {
411 res.push(i);
412 }
413 }
414 return res;
415 };
746 }416 }
747 417
748 function isLeapYear(year) {418 var defaultCalendar = {
749 return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;419 sameDay: '[Today at] LT',
420 nextDay: '[Tomorrow at] LT',
421 nextWeek: 'dddd [at] LT',
422 lastDay: '[Yesterday at] LT',
423 lastWeek: '[Last] dddd [at] LT',
424 sameElse: 'L'
425 };
426
427 function calendar(key, mom, now) {
428 var output = this._calendar[key] || this._calendar['sameElse'];
429 return isFunction(output) ? output.call(mom, now) : output;
750 }430 }
751 431
752 function checkOverflow(m) {432 var defaultLongDateFormat = {
753 var overflow;433 LTS: 'h:mm:ss A',
754 if (m._a && m._pf.overflow === -2) {434 LT: 'h:mm A',
755 overflow =435 L: 'MM/DD/YYYY',
756 m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH :436 LL: 'MMMM D, YYYY',
757 m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE :437 LLL: 'MMMM D, YYYY h:mm A',
758 m._a[HOUR] < 0 || m._a[HOUR] > 24 ||438 LLLL: 'dddd, MMMM D, YYYY h:mm A'
759 (m._a[HOUR] === 24 && (m._a[MINUTE] !== 0 ||439 };
760 m._a[SECOND] !== 0 ||
761 m._a[MILLISECOND] !== 0)) ? HOUR :
762 m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE :
763 m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND :
764 m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND :
765 -1;
766 440
767 if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {441 function longDateFormat(key) {
768 overflow = DATE;442 var format = this._longDateFormat[key],
769 }443 formatUpper = this._longDateFormat[key.toUpperCase()];
770 444
771 m._pf.overflow = overflow;445 if (format || !formatUpper) {
446 return format;
772 }447 }
773 }
774 448
775 function isValid(m) {449 this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
776 if (m._isValid == null) {450 return val.slice(1);
777 m._isValid = !isNaN(m._d.getTime()) &&451 });
778 m._pf.overflow < 0 &&
779 !m._pf.empty &&
780 !m._pf.invalidMonth &&
781 !m._pf.nullInput &&
782 !m._pf.invalidFormat &&
783 !m._pf.userInvalidated;
784 452
785 if (m._strict) {453 return this._longDateFormat[key];
786 m._isValid = m._isValid &&
787 m._pf.charsLeftOver === 0 &&
788 m._pf.unusedTokens.length === 0 &&
789 m._pf.bigHour === undefined;
790 }
791 }
792 return m._isValid;
793 }454 }
794 455
795 function normalizeLocale(key) {456 var defaultInvalidDate = 'Invalid date';
796 return key ? key.toLowerCase().replace('_', '-') : key;457
458 function invalidDate() {
459 return this._invalidDate;
797 }460 }
798 461
799 // pick the locale from the array462 var defaultOrdinal = '%d';
800 // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each463 var defaultDayOfMonthOrdinalParse = /\d{1,2}/;
801 // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
802 function chooseLocale(names) {
803 var i = 0, j, next, locale, split;
804 464
805 while (i < names.length) {465 function ordinal(number) {
806 split = normalizeLocale(names[i]).split('-');466 return this._ordinal.replace('%d', number);
807 j = split.length;
808 next = normalizeLocale(names[i + 1]);
809 next = next ? next.split('-') : null;
810 while (j > 0) {
811 locale = loadLocale(split.slice(0, j).join('-'));
812 if (locale) {
813 return locale;
814 }
815 if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
816 //the next array item is better than a shallower substring of this one
817 break;
818 }
819 j--;
820 }
821 i++;
822 }
823 return null;
824 }467 }
825 468
826 function loadLocale(name) {469 var defaultRelativeTime = {
827 var oldLocale = null;470 future: 'in %s',
828 if (!locales[name] && hasModule) {471 past: '%s ago',
829 try {472 s: 'a few seconds',
830 oldLocale = moment.locale();473 ss: '%d seconds',
831 require('./locale/' + name);474 m: 'a minute',
832 // because defineLocale currently also sets the global locale, we want to undo that for lazy loaded locales475 mm: '%d minutes',
833 moment.locale(oldLocale);476 h: 'an hour',
834 } catch (e) { }477 hh: '%d hours',
835 }478 d: 'a day',
836 return locales[name];479 dd: '%d days',
480 M: 'a month',
481 MM: '%d months',
482 y: 'a year',
483 yy: '%d years'
484 };
485
486 function relativeTime(number, withoutSuffix, string, isFuture) {
487 var output = this._relativeTime[string];
488 return (isFunction(output)) ?
489 output(number, withoutSuffix, string, isFuture) :
490 output.replace(/%d/i, number);
837 }491 }
838 492
839 // Return a moment from input, that is local/utc/utcOffset equivalent to493 function pastFuture(diff, output) {
840 // model.494 var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
841 function makeAs(input, model) {495 return isFunction(format) ? format(output) : format.replace(/%s/i, output);
842 var res, diff;
843 if (model._isUTC) {
844 res = model.clone();
845 diff = (moment.isMoment(input) || isDate(input) ?
846 +input : +moment(input)) - (+res);
847 // Use low-level api, because this fn is low-level api.
848 res._d.setTime(+res._d + diff);
849 moment.updateOffset(res, false);
850 return res;
851 } else {
852 return moment(input).local();
853 }
854 }496 }
855 497
856 /************************************498 var aliases = {};
857 Locale499
858 ************************************/500 function addUnitAlias(unit, shorthand) {
501 var lowerCase = unit.toLowerCase();
502 aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
503 }
859 504
505 function normalizeUnits(units) {
506 return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
507 }
860 508
861 extend(Locale.prototype, {509 function normalizeObjectUnits(inputObject) {
510 var normalizedInput = {},
511 normalizedProp,
512 prop;
862 513
863 set : function (config) {514 for (prop in inputObject) {
864 var prop, i;515 if (hasOwnProp(inputObject, prop)) {
865 for (i in config) {516 normalizedProp = normalizeUnits(prop);
866 prop = config[i];517 if (normalizedProp) {
867 if (typeof prop === 'function') {518 normalizedInput[normalizedProp] = inputObject[prop];
868 this[i] = prop;
869 } else {
870 this['_' + i] = prop;
871 }519 }
872 }520 }
873 // Lenient ordinal parsing accepts just a number in addition to521 }
874 // number + (possibly) stuff coming from _ordinalParseLenient.
875 this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + /\d{1,2}/.source);
876 },
877
878 _months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
879 months : function (m) {
880 return this._months[m.month()];
881 },
882 522
883 _monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),523 return normalizedInput;
884 monthsShort : function (m) {524 }
885 return this._monthsShort[m.month()];
886 },
887 525
888 monthsParse : function (monthName, format, strict) {526 var priorities = {};
889 var i, mom, regex;
890 527
891 if (!this._monthsParse) {528 function addUnitPriority(unit, priority) {
892 this._monthsParse = [];529 priorities[unit] = priority;
893 this._longMonthsParse = [];530 }
894 this._shortMonthsParse = [];
895 }
896 531
897 for (i = 0; i < 12; i++) {532 function getPrioritizedUnits(unitsObj) {
898 // make the regex if we don't have it already533 var units = [];
899 mom = moment.utc([2000, i]);534 for (var u in unitsObj) {
900 if (strict && !this._longMonthsParse[i]) {535 units.push({ unit: u, priority: priorities[u] });
901 this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');536 }
902 this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');537 units.sort(function (a, b) {
903 }538 return a.priority - b.priority;
904 if (!strict && !this._monthsParse[i]) {539 });
905 regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');540 return units;
906 this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');541 }
907 }
908 // test the regex
909 if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
910 return i;
911 } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
912 return i;
913 } else if (!strict && this._monthsParse[i].test(monthName)) {
914 return i;
915 }
916 }
917 },
918 542
919 _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),543 function zeroFill(number, targetLength, forceSign) {
920 weekdays : function (m) {544 var absNumber = '' + Math.abs(number),
921 return this._weekdays[m.day()];545 zerosToFill = targetLength - absNumber.length,
922 },546 sign = number >= 0;
547 return (sign ? (forceSign ? '+' : '') : '-') +
548 Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
549 }
923 550
924 _weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),551 var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
925 weekdaysShort : function (m) {
926 return this._weekdaysShort[m.day()];
927 },
928 552
929 _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),553 var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
930 weekdaysMin : function (m) {
931 return this._weekdaysMin[m.day()];
932 },
933 554
934 weekdaysParse : function (weekdayName) {555 var formatFunctions = {};
935 var i, mom, regex;
936 556
937 if (!this._weekdaysParse) {557 var formatTokenFunctions = {};
938 this._weekdaysParse = [];
939 }
940 558
941 for (i = 0; i < 7; i++) {559 // token: 'M'
942 // make the regex if we don't have it already560 // padded: ['MM', 2]
943 if (!this._weekdaysParse[i]) {561 // ordinal: 'Mo'
944 mom = moment([2000, 1]).day(i);562 // callback: function () { this.month() + 1 }
945 regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');563 function addFormatToken(token, padded, ordinal, callback) {
946 this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');564 var func = callback;
947 }565 if (typeof callback === 'string') {
948 // test the regex566 func = function () {
949 if (this._weekdaysParse[i].test(weekdayName)) {567 return this[callback]();
950 return i;568 };
951 }
952 }
953 },
954
955 _longDateFormat : {
956 LTS : 'h:mm:ss A',
957 LT : 'h:mm A',
958 L : 'MM/DD/YYYY',
959 LL : 'MMMM D, YYYY',
960 LLL : 'MMMM D, YYYY LT',
961 LLLL : 'dddd, MMMM D, YYYY LT'
962 },
963 longDateFormat : function (key) {
964 var output = this._longDateFormat[key];
965 if (!output && this._longDateFormat[key.toUpperCase()]) {
966 output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) {
967 return val.slice(1);
968 });
969 this._longDateFormat[key] = output;
970 }
971 return output;
972 },
973
974 isPM : function (input) {
975 // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
976 // Using charAt should be more compatible.
977 return ((input + '').toLowerCase().charAt(0) === 'p');
978 },
979
980 _meridiemParse : /[ap]\.?m?\.?/i,
981 meridiem : function (hours, minutes, isLower) {
982 if (hours > 11) {
983 return isLower ? 'pm' : 'PM';
984 } else {
985 return isLower ? 'am' : 'AM';
986 }
987 },
988
989
990 _calendar : {
991 sameDay : '[Today at] LT',
992 nextDay : '[Tomorrow at] LT',
993 nextWeek : 'dddd [at] LT',
994 lastDay : '[Yesterday at] LT',
995 lastWeek : '[Last] dddd [at] LT',
996 sameElse : 'L'
997 },
998 calendar : function (key, mom, now) {
999 var output = this._calendar[key];
1000 return typeof output === 'function' ? output.apply(mom, [now]) : output;
1001 },
1002
1003 _relativeTime : {
1004 future : 'in %s',
1005 past : '%s ago',
1006 s : 'a few seconds',
1007 m : 'a minute',
1008 mm : '%d minutes',
1009 h : 'an hour',
1010 hh : '%d hours',
1011 d : 'a day',
1012 dd : '%d days',
1013 M : 'a month',
1014 MM : '%d months',
1015 y : 'a year',
1016 yy : '%d years'
1017 },
1018
1019 relativeTime : function (number, withoutSuffix, string, isFuture) {
1020 var output = this._relativeTime[string];
1021 return (typeof output === 'function') ?
1022 output(number, withoutSuffix, string, isFuture) :
1023 output.replace(/%d/i, number);
1024 },
1025
1026 pastFuture : function (diff, output) {
1027 var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
1028 return typeof format === 'function' ? format(output) : format.replace(/%s/i, output);
1029 },
1030
1031 ordinal : function (number) {
1032 return this._ordinal.replace('%d', number);
1033 },
1034 _ordinal : '%d',
1035 _ordinalParse : /\d{1,2}/,
1036
1037 preparse : function (string) {
1038 return string;
1039 },
1040
1041 postformat : function (string) {
1042 return string;
1043 },
1044
1045 week : function (mom) {
1046 return weekOfYear(mom, this._week.dow, this._week.doy).week;
1047 },
1048
1049 _week : {
1050 dow : 0, // Sunday is the first day of the week.
1051 doy : 6 // The week that contains Jan 1st is the first week of the year.
1052 },
1053
1054 firstDayOfWeek : function () {
1055 return this._week.dow;
1056 },
1057
1058 firstDayOfYear : function () {
1059 return this._week.doy;
1060 },
1061
1062 _invalidDate: 'Invalid date',
1063 invalidDate: function () {
1064 return this._invalidDate;
1065 }569 }
1066 });570 if (token) {
1067 571 formatTokenFunctions[token] = func;
1068 /************************************572 }
1069 Formatting573 if (padded) {
1070 ************************************/574 formatTokenFunctions[padded[0]] = function () {
1071 575 return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
576 };
577 }
578 if (ordinal) {
579 formatTokenFunctions[ordinal] = function () {
580 return this.localeData().ordinal(func.apply(this, arguments), token);
581 };
582 }
583 }
1072 584
1073 function removeFormattingTokens(input) {585 function removeFormattingTokens(input) {
1074 if (input.match(/\[[\s\S]/)) {586 if (input.match(/\[[\s\S]/)) {
@@ -1089,9 +601,9 @@ · 14 unmodified lines
1089 }601 }
1090 602
1091 return function (mom) {603 return function (mom) {
1092 var output = '';604 var output = '', i;
1093 for (i = 0; i < length; i++) {605 for (i = 0; i < length; i++) {
1094 output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];606 output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
1095 }607 }
1096 return output;608 return output;
1097 };609 };
@@ -1104,10 +616,7 @@ · 6 unmodified lines
1104 }616 }
1105 617
1106 format = expandFormat(format, m.localeData());618 format = expandFormat(format, m.localeData());
1107 619 formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
1108 if (!formatFunctions[format]) {
1109 formatFunctions[format] = makeFormatFunction(format);
1110 }
1111 620
1112 return formatFunctions[format](m);621 return formatFunctions[format](m);
1113 }622 }
@@ -1129,982 +638,1278 @@ · 15 unmodified lines
1129 return format;638 return format;
1130 }639 }
1131 640
641 var match1 = /\d/; // 0 - 9
642 var match2 = /\d\d/; // 00 - 99
643 var match3 = /\d{3}/; // 000 - 999
644 var match4 = /\d{4}/; // 0000 - 9999
645 var match6 = /[+-]?\d{6}/; // -999999 - 999999
646 var match1to2 = /\d\d?/; // 0 - 99
647 var match3to4 = /\d\d\d\d?/; // 999 - 9999
648 var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999
649 var match1to3 = /\d{1,3}/; // 0 - 999
650 var match1to4 = /\d{1,4}/; // 0 - 9999
651 var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999
652
653 var matchUnsigned = /\d+/; // 0 - inf
654 var matchSigned = /[+-]?\d+/; // -inf - inf
655
656 var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
657 var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
658
659 var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
1132 660
1133 /************************************661 // any word (or two) characters or numbers including two/three word month in arabic.
1134 Parsing662 // includes scottish gaelic two word and hyphenated months
1135 ************************************/663 var matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;
1136 664
1137 665
1138 // get the regex to find the next token666 var regexes = {};
667
668 function addRegexToken(token, regex, strictRegex) {
669 regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
670 return (isStrict && strictRegex) ? strictRegex : regex;
671 };
672 }
673
1139 function getParseRegexForToken(token, config) {674 function getParseRegexForToken(token, config) {
1140 var a, strict = config._strict;675 if (!hasOwnProp(regexes, token)) {
1141 switch (token) {676 return new RegExp(unescapeFormat(token));
1142 case 'Q':
1143 return parseTokenOneDigit;
1144 case 'DDDD':
1145 return parseTokenThreeDigits;
1146 case 'YYYY':
1147 case 'GGGG':
1148 case 'gggg':
1149 return strict ? parseTokenFourDigits : parseTokenOneToFourDigits;
1150 case 'Y':
1151 case 'G':
1152 case 'g':
1153 return parseTokenSignedNumber;
1154 case 'YYYYYY':
1155 case 'YYYYY':
1156 case 'GGGGG':
1157 case 'ggggg':
1158 return strict ? parseTokenSixDigits : parseTokenOneToSixDigits;
1159 case 'S':
1160 if (strict) {
1161 return parseTokenOneDigit;
1162 }
1163 /* falls through */
1164 case 'SS':
1165 if (strict) {
1166 return parseTokenTwoDigits;
1167 }
1168 /* falls through */
1169 case 'SSS':
1170 if (strict) {
1171 return parseTokenThreeDigits;
1172 }
1173 /* falls through */
1174 case 'DDD':
1175 return parseTokenOneToThreeDigits;
1176 case 'MMM':
1177 case 'MMMM':
1178 case 'dd':
1179 case 'ddd':
1180 case 'dddd':
1181 return parseTokenWord;
1182 case 'a':
1183 case 'A':
1184 return config._locale._meridiemParse;
1185 case 'x':
1186 return parseTokenOffsetMs;
1187 case 'X':
1188 return parseTokenTimestampMs;
1189 case 'Z':
1190 case 'ZZ':
1191 return parseTokenTimezone;
1192 case 'T':
1193 return parseTokenT;
1194 case 'SSSS':
1195 return parseTokenDigits;
1196 case 'MM':
1197 case 'DD':
1198 case 'YY':
1199 case 'GG':
1200 case 'gg':
1201 case 'HH':
1202 case 'hh':
1203 case 'mm':
1204 case 'ss':
1205 case 'ww':
1206 case 'WW':
1207 return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits;
1208 case 'M':
1209 case 'D':
1210 case 'd':
1211 case 'H':
1212 case 'h':
1213 case 'm':
1214 case 's':
1215 case 'w':
1216 case 'W':
1217 case 'e':
1218 case 'E':
1219 return parseTokenOneOrTwoDigits;
1220 case 'Do':
1221 return strict ? config._locale._ordinalParse : config._locale._ordinalParseLenient;
1222 default :
1223 a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i'));
1224 return a;
1225 }677 }
678
679 return regexes[token](config._strict, config._locale);
1226 }680 }
1227 681
1228 function utcOffsetFromString(string) {682 // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
1229 string = string || '';683 function unescapeFormat(s) {
1230 var possibleTzMatches = (string.match(parseTokenTimezone) || []),684 return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
1231 tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [],685 return p1 || p2 || p3 || p4;
1232 parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0],686 }));
1233 minutes = +(parts[1] * 60) + toInt(parts[2]);687 }
1234 688
1235 return parts[0] === '+' ? minutes : -minutes;689 function regexEscape(s) {
690 return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
1236 }691 }
1237 692
1238 // function to convert string input to date693 var tokens = {};
1239 function addTimeToArrayFromToken(token, input, config) {694
1240 var a, datePartArray = config._a;695 function addParseToken(token, callback) {
1241 696 var i, func = callback;
1242 switch (token) {697 if (typeof token === 'string') {
1243 // QUARTER698 token = [token];
1244 case 'Q':699 }
1245 if (input != null) {700 if (isNumber(callback)) {
1246 datePartArray[MONTH] = (toInt(input) - 1) * 3;701 func = function (input, array) {
1247 }702 array[callback] = toInt(input);
1248 break;703 };
1249 // MONTH704 }
1250 case 'M' : // fall through to MM705 for (i = 0; i < token.length; i++) {
1251 case 'MM' :706 tokens[token[i]] = func;
1252 if (input != null) {707 }
1253 datePartArray[MONTH] = toInt(input) - 1;708 }
1254 }709
1255 break;710 function addWeekParseToken(token, callback) {
1256 case 'MMM' : // fall through to MMMM711 addParseToken(token, function (input, array, config, token) {
1257 case 'MMMM' :
1258 a = config._locale.monthsParse(input, token, config._strict);
1259 // if we didn't find a month name, mark the date as invalid.
1260 if (a != null) {
1261 datePartArray[MONTH] = a;
1262 } else {
1263 config._pf.invalidMonth = input;
1264 }
1265 break;
1266 // DAY OF MONTH
1267 case 'D' : // fall through to DD
1268 case 'DD' :
1269 if (input != null) {
1270 datePartArray[DATE] = toInt(input);
1271 }
1272 break;
1273 case 'Do' :
1274 if (input != null) {
1275 datePartArray[DATE] = toInt(parseInt(
1276 input.match(/\d{1,2}/)[0], 10));
1277 }
1278 break;
1279 // DAY OF YEAR
1280 case 'DDD' : // fall through to DDDD
1281 case 'DDDD' :
1282 if (input != null) {
1283 config._dayOfYear = toInt(input);
1284 }
1285
1286 break;
1287 // YEAR
1288 case 'YY' :
1289 datePartArray[YEAR] = moment.parseTwoDigitYear(input);
1290 break;
1291 case 'YYYY' :
1292 case 'YYYYY' :
1293 case 'YYYYYY' :
1294 datePartArray[YEAR] = toInt(input);
1295 break;
1296 // AM / PM
1297 case 'a' : // fall through to A
1298 case 'A' :
1299 config._meridiem = input;
1300 // config._isPm = config._locale.isPM(input);
1301 break;
1302 // HOUR
1303 case 'h' : // fall through to hh
1304 case 'hh' :
1305 config._pf.bigHour = true;
1306 /* falls through */
1307 case 'H' : // fall through to HH
1308 case 'HH' :
1309 datePartArray[HOUR] = toInt(input);
1310 break;
1311 // MINUTE
1312 case 'm' : // fall through to mm
1313 case 'mm' :
1314 datePartArray[MINUTE] = toInt(input);
1315 break;
1316 // SECOND
1317 case 's' : // fall through to ss
1318 case 'ss' :
1319 datePartArray[SECOND] = toInt(input);
1320 break;
1321 // MILLISECOND
1322 case 'S' :
1323 case 'SS' :
1324 case 'SSS' :
1325 case 'SSSS' :
1326 datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000);
1327 break;
1328 // UNIX OFFSET (MILLISECONDS)
1329 case 'x':
1330 config._d = new Date(toInt(input));
1331 break;
1332 // UNIX TIMESTAMP WITH MS
1333 case 'X':
1334 config._d = new Date(parseFloat(input) * 1000);
1335 break;
1336 // TIMEZONE
1337 case 'Z' : // fall through to ZZ
1338 case 'ZZ' :
1339 config._useUTC = true;
1340 config._tzm = utcOffsetFromString(input);
1341 break;
1342 // WEEKDAY - human
1343 case 'dd':
1344 case 'ddd':
1345 case 'dddd':
1346 a = config._locale.weekdaysParse(input);
1347 // if we didn't get a weekday name, mark the date as invalid
1348 if (a != null) {
1349 config._w = config._w || {};
1350 config._w['d'] = a;
1351 } else {
1352 config._pf.invalidWeekday = input;
1353 }
1354 break;
1355 // WEEK, WEEK DAY - numeric
1356 case 'w':
1357 case 'ww':
1358 case 'W':
1359 case 'WW':
1360 case 'd':
1361 case 'e':
1362 case 'E':
1363 token = token.substr(0, 1);
1364 /* falls through */
1365 case 'gggg':
1366 case 'GGGG':
1367 case 'GGGGG':
1368 token = token.substr(0, 2);
1369 if (input) {
1370 config._w = config._w || {};
1371 config._w[token] = toInt(input);
1372 }
1373 break;
1374 case 'gg':
1375 case 'GG':
1376 config._w = config._w || {};712 config._w = config._w || {};
1377 config._w[token] = moment.parseTwoDigitYear(input);713 callback(input, config._w, config, token);
714 });
715 }
716
717 function addTimeToArrayFromToken(token, input, config) {
718 if (input != null && hasOwnProp(tokens, token)) {
719 tokens[token](input, config._a, config, token);
1378 }720 }
1379 }721 }
1380 722
1381 function dayOfYearFromWeekInfo(config) {723 var YEAR = 0;
1382 var w, weekYear, week, weekday, dow, doy, temp;724 var MONTH = 1;
725 var DATE = 2;
726 var HOUR = 3;
727 var MINUTE = 4;
728 var SECOND = 5;
729 var MILLISECOND = 6;
730 var WEEK = 7;
731 var WEEKDAY = 8;
732
733 // FORMATTING
734
735 addFormatToken('Y', 0, 0, function () {
736 var y = this.year();
737 return y <= 9999 ? '' + y : '+' + y;
738 });
1383 739
1384 w = config._w;740 addFormatToken(0, ['YY', 2], 0, function () {
1385 if (w.GG != null || w.W != null || w.E != null) {741 return this.year() % 100;
1386 dow = 1;742 });
1387 doy = 4;
1388 743
1389 // TODO: We need to take the current isoWeekYear, but that depends on744 addFormatToken(0, ['YYYY', 4], 0, 'year');
1390 // how we interpret now (local, utc, fixed offset). So create745 addFormatToken(0, ['YYYYY', 5], 0, 'year');
1391 // a now version of current config (take local/utc/offset flags, and746 addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
1392 // create now).
1393 weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year);
1394 week = dfl(w.W, 1);
1395 weekday = dfl(w.E, 1);
1396 } else {
1397 dow = config._locale._week.dow;
1398 doy = config._locale._week.doy;
1399 747
1400 weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year);748 // ALIASES
1401 week = dfl(w.w, 1);
1402 749
1403 if (w.d != null) {750 addUnitAlias('year', 'y');
1404 // weekday -- low day numbers are considered next week751
1405 weekday = w.d;752 // PRIORITIES
1406 if (weekday < dow) {753
1407 ++week;754 addUnitPriority('year', 1);
1408 }755
1409 } else if (w.e != null) {756 // PARSING
1410 // local weekday -- counting starts from begining of week757
1411 weekday = w.e + dow;758 addRegexToken('Y', matchSigned);
1412 } else {759 addRegexToken('YY', match1to2, match2);
1413 // default to begining of week760 addRegexToken('YYYY', match1to4, match4);
1414 weekday = dow;761 addRegexToken('YYYYY', match1to6, match6);
1415 }762 addRegexToken('YYYYYY', match1to6, match6);
1416 }763
1417 temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow);764 addParseToken(['YYYYY', 'YYYYYY'], YEAR);
765 addParseToken('YYYY', function (input, array) {
766 array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
767 });
768 addParseToken('YY', function (input, array) {
769 array[YEAR] = hooks.parseTwoDigitYear(input);
770 });
771 addParseToken('Y', function (input, array) {
772 array[YEAR] = parseInt(input, 10);
773 });
774
775 // HELPERS
1418 776
1419 config._a[YEAR] = temp.year;777 function daysInYear(year) {
1420 config._dayOfYear = temp.dayOfYear;778 return isLeapYear(year) ? 366 : 365;
1421 }779 }
1422 780
1423 // convert an array to a date.781 function isLeapYear(year) {
1424 // the array should mirror the parameters below782 return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
1425 // note: all values past the year are optional and will default to the lowest possible value.783 }
1426 // [year, month, day , hour, minute, second, millisecond]
1427 function dateFromConfig(config) {
1428 var i, date, input = [], currentDate, yearToUse;
1429 784
1430 if (config._d) {785 // HOOKS
1431 return;
1432 }
1433 786
1434 currentDate = currentDateArray(config);787 hooks.parseTwoDigitYear = function (input) {
788 return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
789 };
1435 790
1436 //compute day of the year from weeks and weekdays791 // MOMENTS
1437 if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
1438 dayOfYearFromWeekInfo(config);
1439 }
1440 792
1441 //if the day of the year is set, figure out what it is793 var getSetYear = makeGetSet('FullYear', true);
1442 if (config._dayOfYear) {
1443 yearToUse = dfl(config._a[YEAR], currentDate[YEAR]);
1444 794
1445 if (config._dayOfYear > daysInYear(yearToUse)) {795 function getIsLeapYear() {
1446 config._pf._overflowDayOfYear = true;796 return isLeapYear(this.year());
797 }
798
799 function makeGetSet(unit, keepTime) {
800 return function (value) {
801 if (value != null) {
802 set$1(this, unit, value);
803 hooks.updateOffset(this, keepTime);
804 return this;
805 } else {
806 return get(this, unit);
1447 }807 }
808 };
809 }
1448 810
1449 date = makeUTCDate(yearToUse, 0, config._dayOfYear);811 function get(mom, unit) {
1450 config._a[MONTH] = date.getUTCMonth();812 return mom.isValid() ?
1451 config._a[DATE] = date.getUTCDate();813 mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
814 }
815
816 function set$1(mom, unit, value) {
817 if (mom.isValid() && !isNaN(value)) {
818 if (unit === 'FullYear' && isLeapYear(mom.year()) && mom.month() === 1 && mom.date() === 29) {
819 mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month()));
820 }
821 else {
822 mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
823 }
1452 }824 }
825 }
1453 826
1454 // Default to current date.827 // MOMENTS
1455 // * if no year, month, day of month are given, default to today
1456 // * if day of month is given, default month and year
1457 // * if month is given, default only year
1458 // * if year is given, don't default anything
1459 for (i = 0; i < 3 && config._a[i] == null; ++i) {
1460 config._a[i] = input[i] = currentDate[i];
1461 }
1462 828
1463 // Zero out whatever was not defaulted, including time829 function stringGet(units) {
1464 for (; i < 7; i++) {830 units = normalizeUnits(units);
1465 config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];831 if (isFunction(this[units])) {
1466 }832 return this[units]();
1467
1468 // Check for 24:00:00.000
1469 if (config._a[HOUR] === 24 &&
1470 config._a[MINUTE] === 0 &&
1471 config._a[SECOND] === 0 &&
1472 config._a[MILLISECOND] === 0) {
1473 config._nextDay = true;
1474 config._a[HOUR] = 0;
1475 }833 }
834 return this;
835 }
1476 836
1477 config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input);
1478 // Apply timezone offset from input. The actual utcOffset can be changed
1479 // with parseZone.
1480 if (config._tzm != null) {
1481 config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
1482 }
1483 837
1484 if (config._nextDay) {838 function stringSet(units, value) {
1485 config._a[HOUR] = 24;839 if (typeof units === 'object') {
840 units = normalizeObjectUnits(units);
841 var prioritized = getPrioritizedUnits(units);
842 for (var i = 0; i < prioritized.length; i++) {
843 this[prioritized[i].unit](units[prioritized[i].unit]);
844 }
845 } else {
846 units = normalizeUnits(units);
847 if (isFunction(this[units])) {
848 return this[units](value);
849 }
1486 }850 }
851 return this;
1487 }852 }
1488 853
1489 function dateFromObject(config) {854 function mod(n, x) {
1490 var normalizedInput;855 return ((n % x) + x) % x;
1491 856 }
1492 if (config._d) {
1493 return;
1494 }
1495 857
1496 normalizedInput = normalizeObjectUnits(config._i);858 var indexOf;
1497 config._a = [
1498 normalizedInput.year,
1499 normalizedInput.month,
1500 normalizedInput.day || normalizedInput.date,
1501 normalizedInput.hour,
1502 normalizedInput.minute,
1503 normalizedInput.second,
1504 normalizedInput.millisecond
1505 ];
1506 859
1507 dateFromConfig(config);860 if (Array.prototype.indexOf) {
861 indexOf = Array.prototype.indexOf;
862 } else {
863 indexOf = function (o) {
864 // I know
865 var i;
866 for (i = 0; i < this.length; ++i) {
867 if (this[i] === o) {
868 return i;
869 }
870 }
871 return -1;
872 };
1508 }873 }
1509 874
1510 function currentDateArray(config) {875 function daysInMonth(year, month) {
1511 var now = new Date();876 if (isNaN(year) || isNaN(month)) {
1512 if (config._useUTC) {877 return NaN;
1513 return [
1514 now.getUTCFullYear(),
1515 now.getUTCMonth(),
1516 now.getUTCDate()
1517 ];
1518 } else {
1519 return [now.getFullYear(), now.getMonth(), now.getDate()];
1520 }878 }
879 var modMonth = mod(month, 12);
880 year += (month - modMonth) / 12;
881 return modMonth === 1 ? (isLeapYear(year) ? 29 : 28) : (31 - modMonth % 7 % 2);
1521 }882 }
1522 883
1523 // date from string and format string884 // FORMATTING
1524 function makeDateFromStringAndFormat(config) {
1525 if (config._f === moment.ISO_8601) {
1526 parseISO(config);
1527 return;
1528 }
1529 885
1530 config._a = [];886 addFormatToken('M', ['MM', 2], 'Mo', function () {
1531 config._pf.empty = true;887 return this.month() + 1;
888 });
1532 889
1533 // This array is used to make a Date, either with `new Date` or `Date.UTC`890 addFormatToken('MMM', 0, 0, function (format) {
1534 var string = '' + config._i,891 return this.localeData().monthsShort(this, format);
1535 i, parsedInput, tokens, token, skipped,892 });
1536 stringLength = string.length,
1537 totalParsedInputLength = 0;
1538 893
1539 tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];894 addFormatToken('MMMM', 0, 0, function (format) {
895 return this.localeData().months(this, format);
896 });
1540 897
1541 for (i = 0; i < tokens.length; i++) {898 // ALIASES
1542 token = tokens[i];
1543 parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
1544 if (parsedInput) {
1545 skipped = string.substr(0, string.indexOf(parsedInput));
1546 if (skipped.length > 0) {
1547 config._pf.unusedInput.push(skipped);
1548 }
1549 string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
1550 totalParsedInputLength += parsedInput.length;
1551 }
1552 // don't parse if it's not a known token
1553 if (formatTokenFunctions[token]) {
1554 if (parsedInput) {
1555 config._pf.empty = false;
1556 }
1557 else {
1558 config._pf.unusedTokens.push(token);
1559 }
1560 addTimeToArrayFromToken(token, parsedInput, config);
1561 }
1562 else if (config._strict && !parsedInput) {
1563 config._pf.unusedTokens.push(token);
1564 }
1565 }
1566 899
1567 // add remaining unparsed input length to the string900 addUnitAlias('month', 'M');
1568 config._pf.charsLeftOver = stringLength - totalParsedInputLength;901
1569 if (string.length > 0) {902 // PRIORITY
1570 config._pf.unusedInput.push(string);903
904 addUnitPriority('month', 8);
905
906 // PARSING
907
908 addRegexToken('M', match1to2);
909 addRegexToken('MM', match1to2, match2);
910 addRegexToken('MMM', function (isStrict, locale) {
911 return locale.monthsShortRegex(isStrict);
912 });
913 addRegexToken('MMMM', function (isStrict, locale) {
914 return locale.monthsRegex(isStrict);
915 });
916
917 addParseToken(['M', 'MM'], function (input, array) {
918 array[MONTH] = toInt(input) - 1;
919 });
920
921 addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
922 var month = config._locale.monthsParse(input, token, config._strict);
923 // if we didn't find a month name, mark the date as invalid.
924 if (month != null) {
925 array[MONTH] = month;
926 } else {
927 getParsingFlags(config).invalidMonth = input;
1571 }928 }
929 });
1572 930
1573 // clear _12h flag if hour is <= 12931 // LOCALES
1574 if (config._pf.bigHour === true && config._a[HOUR] <= 12) {932
1575 config._pf.bigHour = undefined;933 var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
934 var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
935 function localeMonths(m, format) {
936 if (!m) {
937 return isArray(this._months) ? this._months :
938 this._months['standalone'];
1576 }939 }
1577 // handle meridiem940 return isArray(this._months) ? this._months[m.month()] :
1578 config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR],941 this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
1579 config._meridiem);
1580 dateFromConfig(config);
1581 checkOverflow(config);
1582 }942 }
1583 943
1584 function unescapeFormat(s) {944 var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
1585 return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {945 function localeMonthsShort(m, format) {
1586 return p1 || p2 || p3 || p4;946 if (!m) {
1587 });947 return isArray(this._monthsShort) ? this._monthsShort :
948 this._monthsShort['standalone'];
949 }
950 return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
951 this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
1588 }952 }
1589 953
1590 // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript954 function handleStrictParse(monthName, format, strict) {
1591 function regexpEscape(s) {955 var i, ii, mom, llc = monthName.toLocaleLowerCase();
1592 return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');956 if (!this._monthsParse) {
957 // this is not used
958 this._monthsParse = [];
959 this._longMonthsParse = [];
960 this._shortMonthsParse = [];
961 for (i = 0; i < 12; ++i) {
962 mom = createUTC([2000, i]);
963 this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
964 this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
965 }
966 }
967
968 if (strict) {
969 if (format === 'MMM') {
970 ii = indexOf.call(this._shortMonthsParse, llc);
971 return ii !== -1 ? ii : null;
972 } else {
973 ii = indexOf.call(this._longMonthsParse, llc);
974 return ii !== -1 ? ii : null;
975 }
976 } else {
977 if (format === 'MMM') {
978 ii = indexOf.call(this._shortMonthsParse, llc);
979 if (ii !== -1) {
980 return ii;
981 }
982 ii = indexOf.call(this._longMonthsParse, llc);
983 return ii !== -1 ? ii : null;
984 } else {
985 ii = indexOf.call(this._longMonthsParse, llc);
986 if (ii !== -1) {
987 return ii;
988 }
989 ii = indexOf.call(this._shortMonthsParse, llc);
990 return ii !== -1 ? ii : null;
991 }
992 }
1593 }993 }
1594 994
1595 // date from string and array of format strings995 function localeMonthsParse(monthName, format, strict) {
1596 function makeDateFromStringAndArray(config) {996 var i, mom, regex;
1597 var tempConfig,
1598 bestMoment,
1599 997
1600 scoreToBeat,998 if (this._monthsParseExact) {
1601 i,999 return handleStrictParse.call(this, monthName, format, strict);
1602 currentScore;1000 }
1603 1001
1604 if (config._f.length === 0) {1002 if (!this._monthsParse) {
1605 config._pf.invalidFormat = true;1003 this._monthsParse = [];
1606 config._d = new Date(NaN);1004 this._longMonthsParse = [];
1607 return;1005 this._shortMonthsParse = [];
1608 }1006 }
1609 1007
1610 for (i = 0; i < config._f.length; i++) {1008 // TODO: add sorting
1611 currentScore = 0;1009 // Sorting makes sure if one month (or abbr) is a prefix of another
1612 tempConfig = copyConfig({}, config);1010 // see sorting in computeMonthsParse
1613 if (config._useUTC != null) {1011 for (i = 0; i < 12; i++) {
1614 tempConfig._useUTC = config._useUTC;1012 // make the regex if we don't have it already
1013 mom = createUTC([2000, i]);
1014 if (strict && !this._longMonthsParse[i]) {
1015 this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
1016 this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
1615 }1017 }
1616 tempConfig._pf = defaultParsingFlags();1018 if (!strict && !this._monthsParse[i]) {
1617 tempConfig._f = config._f[i];1019 regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
1618 makeDateFromStringAndFormat(tempConfig);1020 this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
1619 1021 }
1620 if (!isValid(tempConfig)) {1022 // test the regex
1621 continue;1023 if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
1024 return i;
1025 } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
1026 return i;
1027 } else if (!strict && this._monthsParse[i].test(monthName)) {
1028 return i;
1622 }1029 }
1030 }
1031 }
1623 1032
1624 // if there is any input that was not parsed add a penalty for that format1033 // MOMENTS
1625 currentScore += tempConfig._pf.charsLeftOver;
1626 1034
1627 //or tokens1035 function setMonth(mom, value) {
1628 currentScore += tempConfig._pf.unusedTokens.length * 10;1036 var dayOfMonth;
1629 1037
1630 tempConfig._pf.score = currentScore;1038 if (!mom.isValid()) {
1039 // No op
1040 return mom;
1041 }
1631 1042
1632 if (scoreToBeat == null || currentScore < scoreToBeat) {1043 if (typeof value === 'string') {
1633 scoreToBeat = currentScore;1044 if (/^\d+$/.test(value)) {
1634 bestMoment = tempConfig;1045 value = toInt(value);
1046 } else {
1047 value = mom.localeData().monthsParse(value);
1048 // TODO: Another silent failure?
1049 if (!isNumber(value)) {
1050 return mom;
1051 }
1635 }1052 }
1636 }1053 }
1637 1054
1638 extend(config, bestMoment || tempConfig);1055 dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
1056 mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
1057 return mom;
1639 }1058 }
1640 1059
1641 // date from iso format1060 function getSetMonth(value) {
1642 function parseISO(config) {1061 if (value != null) {
1643 var i, l,1062 setMonth(this, value);
1644 string = config._i,1063 hooks.updateOffset(this, true);
1645 match = isoRegex.exec(string);1064 return this;
1065 } else {
1066 return get(this, 'Month');
1067 }
1068 }
1646 1069
1647 if (match) {1070 function getDaysInMonth() {
1648 config._pf.iso = true;1071 return daysInMonth(this.year(), this.month());
1649 for (i = 0, l = isoDates.length; i < l; i++) {1072 }
1650 if (isoDates[i][1].exec(string)) {1073
1651 // match[5] should be 'T' or undefined1074 var defaultMonthsShortRegex = matchWord;
1652 config._f = isoDates[i][0] + (match[6] || ' ');1075 function monthsShortRegex(isStrict) {
1653 break;1076 if (this._monthsParseExact) {
1654 }1077 if (!hasOwnProp(this, '_monthsRegex')) {
1655 }1078 computeMonthsParse.call(this);
1656 for (i = 0, l = isoTimes.length; i < l; i++) {
1657 if (isoTimes[i][1].exec(string)) {
1658 config._f += isoTimes[i][0];
1659 break;
1660 }
1661 }1079 }
1662 if (string.match(parseTokenTimezone)) {1080 if (isStrict) {
1663 config._f += 'Z';1081 return this._monthsShortStrictRegex;
1082 } else {
1083 return this._monthsShortRegex;
1664 }1084 }
1665 makeDateFromStringAndFormat(config);
1666 } else {1085 } else {
1667 config._isValid = false;1086 if (!hasOwnProp(this, '_monthsShortRegex')) {
1087 this._monthsShortRegex = defaultMonthsShortRegex;
1088 }
1089 return this._monthsShortStrictRegex && isStrict ?
1090 this._monthsShortStrictRegex : this._monthsShortRegex;
1668 }1091 }
1669 }1092 }
1670 1093
1671 // date from iso format or fallback1094 var defaultMonthsRegex = matchWord;
1672 function makeDateFromString(config) {1095 function monthsRegex(isStrict) {
1673 parseISO(config);1096 if (this._monthsParseExact) {
1674 if (config._isValid === false) {1097 if (!hasOwnProp(this, '_monthsRegex')) {
1675 delete config._isValid;1098 computeMonthsParse.call(this);
1676 moment.createFromInputFallback(config);1099 }
1100 if (isStrict) {
1101 return this._monthsStrictRegex;
1102 } else {
1103 return this._monthsRegex;
1104 }
1105 } else {
1106 if (!hasOwnProp(this, '_monthsRegex')) {
1107 this._monthsRegex = defaultMonthsRegex;
1108 }
1109 return this._monthsStrictRegex && isStrict ?
1110 this._monthsStrictRegex : this._monthsRegex;
1677 }1111 }
1678 }1112 }
1679 1113
1680 function map(arr, fn) {1114 function computeMonthsParse() {
1681 var res = [], i;1115 function cmpLenRev(a, b) {
1682 for (i = 0; i < arr.length; ++i) {1116 return b.length - a.length;
1683 res.push(fn(arr[i], i));
1684 }1117 }
1685 return res;
1686 }
1687 1118
1688 function makeDateFromInput(config) {1119 var shortPieces = [], longPieces = [], mixedPieces = [],
1689 var input = config._i, matched;1120 i, mom;
1690 if (input === undefined) {1121 for (i = 0; i < 12; i++) {
1691 config._d = new Date();1122 // make the regex if we don't have it already
1692 } else if (isDate(input)) {1123 mom = createUTC([2000, i]);
1693 config._d = new Date(+input);1124 shortPieces.push(this.monthsShort(mom, ''));
1694 } else if ((matched = aspNetJsonRegex.exec(input)) !== null) {1125 longPieces.push(this.months(mom, ''));
1695 config._d = new Date(+matched[1]);1126 mixedPieces.push(this.months(mom, ''));
1696 } else if (typeof input === 'string') {1127 mixedPieces.push(this.monthsShort(mom, ''));
1697 makeDateFromString(config);1128 }
1698 } else if (isArray(input)) {1129 // Sorting makes sure if one month (or abbr) is a prefix of another it
1699 config._a = map(input.slice(0), function (obj) {1130 // will match the longer piece.
1700 return parseInt(obj, 10);1131 shortPieces.sort(cmpLenRev);
1701 });1132 longPieces.sort(cmpLenRev);
1702 dateFromConfig(config);1133 mixedPieces.sort(cmpLenRev);
1703 } else if (typeof(input) === 'object') {1134 for (i = 0; i < 12; i++) {
1704 dateFromObject(config);1135 shortPieces[i] = regexEscape(shortPieces[i]);
1705 } else if (typeof(input) === 'number') {1136 longPieces[i] = regexEscape(longPieces[i]);
1706 // from milliseconds1137 }
1707 config._d = new Date(input);1138 for (i = 0; i < 24; i++) {
1708 } else {1139 mixedPieces[i] = regexEscape(mixedPieces[i]);
1709 moment.createFromInputFallback(config);
1710 }1140 }
1141
1142 this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
1143 this._monthsShortRegex = this._monthsRegex;
1144 this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
1145 this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
1711 }1146 }
1712 1147
1713 function makeDate(y, m, d, h, M, s, ms) {1148 function createDate(y, m, d, h, M, s, ms) {
1714 //can't just apply() to create a date:1149 // can't just apply() to create a date:
1715 //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply1150 // https://stackoverflow.com/q/181348
1716 var date = new Date(y, m, d, h, M, s, ms);1151 var date = new Date(y, m, d, h, M, s, ms);
1717 1152
1718 //the date constructor doesn't accept years < 19701153 // the date constructor remaps years 0-99 to 1900-1999
1719 if (y < 1970) {1154 if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
1720 date.setFullYear(y);1155 date.setFullYear(y);
1721 }1156 }
1722 return date;1157 return date;
1723 }1158 }
1724 1159
1725 function makeUTCDate(y) {1160 function createUTCDate(y) {
1726 var date = new Date(Date.UTC.apply(null, arguments));1161 var date = new Date(Date.UTC.apply(null, arguments));
1727 if (y < 1970) {1162
1163 // the Date.UTC function remaps years 0-99 to 1900-1999
1164 if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
1728 date.setUTCFullYear(y);1165 date.setUTCFullYear(y);
1729 }1166 }
1730 return date;1167 return date;
1731 }1168 }
1732 1169
1733 function parseWeekday(input, locale) {1170 // start-of-first-week - start-of-year
1734 if (typeof input === 'string') {1171 function firstWeekOffset(year, dow, doy) {
1735 if (!isNaN(input)) {1172 var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
1736 input = parseInt(input, 10);1173 fwd = 7 + dow - doy,
1737 }1174 // first-week day local weekday -- which local weekday is fwd
1738 else {1175 fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
1739 input = locale.weekdaysParse(input);1176
1740 if (typeof input !== 'number') {1177 return -fwdlw + fwd - 1;
1741 return null;1178 }
1742 }1179
1743 }1180 // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
1181 function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
1182 var localWeekday = (7 + weekday - dow) % 7,
1183 weekOffset = firstWeekOffset(year, dow, doy),
1184 dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
1185 resYear, resDayOfYear;
1186
1187 if (dayOfYear <= 0) {
1188 resYear = year - 1;
1189 resDayOfYear = daysInYear(resYear) + dayOfYear;
1190 } else if (dayOfYear > daysInYear(year)) {
1191 resYear = year + 1;
1192 resDayOfYear = dayOfYear - daysInYear(year);
1193 } else {
1194 resYear = year;
1195 resDayOfYear = dayOfYear;
1744 }1196 }
1745 return input;1197
1198 return {
1199 year: resYear,
1200 dayOfYear: resDayOfYear
1201 };
1746 }1202 }
1747 1203
1748 /************************************1204 function weekOfYear(mom, dow, doy) {
1749 Relative Time1205 var weekOffset = firstWeekOffset(mom.year(), dow, doy),
1750 ************************************/1206 week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
1207 resWeek, resYear;
1208
1209 if (week < 1) {
1210 resYear = mom.year() - 1;
1211 resWeek = week + weeksInYear(resYear, dow, doy);
1212 } else if (week > weeksInYear(mom.year(), dow, doy)) {
1213 resWeek = week - weeksInYear(mom.year(), dow, doy);
1214 resYear = mom.year() + 1;
1215 } else {
1216 resYear = mom.year();
1217 resWeek = week;
1218 }
1751 1219
1220 return {
1221 week: resWeek,
1222 year: resYear
1223 };
1224 }
1752 1225
1753 // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize1226 function weeksInYear(year, dow, doy) {
1754 function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {1227 var weekOffset = firstWeekOffset(year, dow, doy),
1755 return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);1228 weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
1229 return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
1756 }1230 }
1757 1231
1758 function relativeTime(posNegDuration, withoutSuffix, locale) {1232 // FORMATTING
1759 var duration = moment.duration(posNegDuration).abs(),
1760 seconds = round(duration.as('s')),
1761 minutes = round(duration.as('m')),
1762 hours = round(duration.as('h')),
1763 days = round(duration.as('d')),
1764 months = round(duration.as('M')),
1765 years = round(duration.as('y')),
1766 1233
1767 args = seconds < relativeTimeThresholds.s && ['s', seconds] ||1234 addFormatToken('w', ['ww', 2], 'wo', 'week');
1768 minutes === 1 && ['m'] ||1235 addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
1769 minutes < relativeTimeThresholds.m && ['mm', minutes] ||
1770 hours === 1 && ['h'] ||
1771 hours < relativeTimeThresholds.h && ['hh', hours] ||
1772 days === 1 && ['d'] ||
1773 days < relativeTimeThresholds.d && ['dd', days] ||
1774 months === 1 && ['M'] ||
1775 months < relativeTimeThresholds.M && ['MM', months] ||
1776 years === 1 && ['y'] || ['yy', years];
1777 1236
1778 args[2] = withoutSuffix;1237 // ALIASES
1779 args[3] = +posNegDuration > 0;
1780 args[4] = locale;
1781 return substituteTimeAgo.apply({}, args);
1782 }
1783 1238
1239 addUnitAlias('week', 'w');
1240 addUnitAlias('isoWeek', 'W');
1784 1241
1785 /************************************1242 // PRIORITIES
1786 Week of Year
1787 ************************************/
1788 1243
1244 addUnitPriority('week', 5);
1245 addUnitPriority('isoWeek', 5);
1789 1246
1790 // firstDayOfWeek 0 = sun, 6 = sat1247 // PARSING
1791 // the day of the week that starts the week
1792 // (usually sunday or monday)
1793 // firstDayOfWeekOfYear 0 = sun, 6 = sat
1794 // the first week is the week that contains the first
1795 // of this day of the week
1796 // (eg. ISO weeks use thursday (4))
1797 function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
1798 var end = firstDayOfWeekOfYear - firstDayOfWeek,
1799 daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(),
1800 adjustedMoment;
1801 1248
1249 addRegexToken('w', match1to2);
1250 addRegexToken('ww', match1to2, match2);
1251 addRegexToken('W', match1to2);
1252 addRegexToken('WW', match1to2, match2);
1802 1253
1803 if (daysToDayOfWeek > end) {1254 addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
1804 daysToDayOfWeek -= 7;1255 week[token.substr(0, 1)] = toInt(input);
1805 }1256 });
1806 1257
1807 if (daysToDayOfWeek < end - 7) {1258 // HELPERS
1808 daysToDayOfWeek += 7;
1809 }
1810 1259
1811 adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd');1260 // LOCALES
1812 return {1261
1813 week: Math.ceil(adjustedMoment.dayOfYear() / 7),1262 function localeWeek(mom) {
1814 year: adjustedMoment.year()1263 return weekOfYear(mom, this._week.dow, this._week.doy).week;
1815 };
1816 }1264 }
1817 1265
1818 //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday1266 var defaultLocaleWeek = {
1819 function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) {1267 dow: 0, // Sunday is the first day of the week.
1820 var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear;1268 doy: 6 // The week that contains Jan 1st is the first week of the year.
1269 };
1821 1270
1822 d = d === 0 ? 7 : d;1271 function localeFirstDayOfWeek() {
1823 weekday = weekday != null ? weekday : firstDayOfWeek;1272 return this._week.dow;
1824 daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0);1273 }
1825 dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1;
1826 1274
1827 return {1275 function localeFirstDayOfYear() {
1828 year: dayOfYear > 0 ? year : year - 1,1276 return this._week.doy;
1829 dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear
1830 };
1831 }1277 }
1832 1278
1833 /************************************1279 // MOMENTS
1834 Top Level Functions
1835 ************************************/
1836 1280
1837 function makeMoment(config) {1281 function getSetWeek(input) {
1838 var input = config._i,1282 var week = this.localeData().week(this);
1839 format = config._f,1283 return input == null ? week : this.add((input - week) * 7, 'd');
1840 res;1284 }
1841 1285
1842 config._locale = config._locale || moment.localeData(config._l);1286 function getSetISOWeek(input) {
1287 var week = weekOfYear(this, 1, 4).week;
1288 return input == null ? week : this.add((input - week) * 7, 'd');
1289 }
1843 1290
1844 if (input === null || (format === undefined && input === '')) {1291 // FORMATTING
1845 return moment.invalid({nullInput: true});
1846 }
1847 1292
1848 if (typeof input === 'string') {1293 addFormatToken('d', 0, 'do', 'day');
1849 config._i = input = config._locale.preparse(input);
1850 }
1851 1294
1852 if (moment.isMoment(input)) {1295 addFormatToken('dd', 0, 0, function (format) {
1853 return new Moment(input, true);1296 return this.localeData().weekdaysMin(this, format);
1854 } else if (format) {1297 });
1855 if (isArray(format)) {
1856 makeDateFromStringAndArray(config);
1857 } else {
1858 makeDateFromStringAndFormat(config);
1859 }
1860 } else {
1861 makeDateFromInput(config);
1862 }
1863 1298
1864 res = new Moment(config);1299 addFormatToken('ddd', 0, 0, function (format) {
1865 if (res._nextDay) {1300 return this.localeData().weekdaysShort(this, format);
1866 // Adding is smart enough around DST1301 });
1867 res.add(1, 'd');
1868 res._nextDay = undefined;
1869 }
1870 1302
1871 return res;1303 addFormatToken('dddd', 0, 0, function (format) {
1872 }1304 return this.localeData().weekdays(this, format);
1305 });
1873 1306
1874 moment = function (input, format, locale, strict) {1307 addFormatToken('e', 0, 0, 'weekday');
1875 var c;1308 addFormatToken('E', 0, 0, 'isoWeekday');
1876 1309
1877 if (typeof(locale) === 'boolean') {1310 // ALIASES
1878 strict = locale;1311
1879 locale = undefined;1312 addUnitAlias('day', 'd');
1313 addUnitAlias('weekday', 'e');
1314 addUnitAlias('isoWeekday', 'E');
1315
1316 // PRIORITY
1317 addUnitPriority('day', 11);
1318 addUnitPriority('weekday', 11);
1319 addUnitPriority('isoWeekday', 11);
1320
1321 // PARSING
1322
1323 addRegexToken('d', match1to2);
1324 addRegexToken('e', match1to2);
1325 addRegexToken('E', match1to2);
1326 addRegexToken('dd', function (isStrict, locale) {
1327 return locale.weekdaysMinRegex(isStrict);
1328 });
1329 addRegexToken('ddd', function (isStrict, locale) {
1330 return locale.weekdaysShortRegex(isStrict);
1331 });
1332 addRegexToken('dddd', function (isStrict, locale) {
1333 return locale.weekdaysRegex(isStrict);
1334 });
1335
1336 addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
1337 var weekday = config._locale.weekdaysParse(input, token, config._strict);
1338 // if we didn't get a weekday name, mark the date as invalid
1339 if (weekday != null) {
1340 week.d = weekday;
1341 } else {
1342 getParsingFlags(config).invalidWeekday = input;
1880 }1343 }
1881 // object construction must be done this way.1344 });
1882 // https://github.com/moment/moment/issues/1423
1883 c = {};
1884 c._isAMomentObject = true;
1885 c._i = input;
1886 c._f = format;
1887 c._l = locale;
1888 c._strict = strict;
1889 c._isUTC = false;
1890 c._pf = defaultParsingFlags();
1891 1345
1892 return makeMoment(c);1346 addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
1893 };1347 week[token] = toInt(input);
1348 });
1894 1349
1895 moment.suppressDeprecationWarnings = false;1350 // HELPERS
1896 1351
1897 moment.createFromInputFallback = deprecate(1352 function parseWeekday(input, locale) {
1898 'moment construction falls back to js Date. This is ' +1353 if (typeof input !== 'string') {
1899 'discouraged and will be removed in upcoming major ' +1354 return input;
1900 'release. Please refer to ' +
1901 'https://github.com/moment/moment/issues/1407 for more info.',
1902 function (config) {
1903 config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
1904 }1355 }
1905 );
1906 1356
1907 // Pick a moment m from moments so that m[fn](other) is true for all1357 if (!isNaN(input)) {
1908 // other. This relies on the function fn to be transitive.1358 return parseInt(input, 10);
1909 //
1910 // moments should either be an array of moment objects or an array, whose
1911 // first element is an array of moment objects.
1912 function pickBy(fn, moments) {
1913 var res, i;
1914 if (moments.length === 1 && isArray(moments[0])) {
1915 moments = moments[0];
1916 }1359 }
1917 if (!moments.length) {1360
1918 return moment();1361 input = locale.weekdaysParse(input);
1362 if (typeof input === 'number') {
1363 return input;
1919 }1364 }
1920 res = moments[0];1365
1921 for (i = 1; i < moments.length; ++i) {1366 return null;
1922 if (moments[i][fn](res)) {1367 }
1923 res = moments[i];1368
1369 function parseIsoWeekday(input, locale) {
1370 if (typeof input === 'string') {
1371 return locale.weekdaysParse(input) % 7 || 7;
1372 }
1373 return isNaN(input) ? null : input;
1374 }
1375
1376 // LOCALES
1377
1378 var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
1379 function localeWeekdays(m, format) {
1380 if (!m) {
1381 return isArray(this._weekdays) ? this._weekdays :
1382 this._weekdays['standalone'];
1383 }
1384 return isArray(this._weekdays) ? this._weekdays[m.day()] :
1385 this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
1386 }
1387
1388 var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
1389 function localeWeekdaysShort(m) {
1390 return (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort;
1391 }
1392
1393 var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
1394 function localeWeekdaysMin(m) {
1395 return (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin;
1396 }
1397
1398 function handleStrictParse$1(weekdayName, format, strict) {
1399 var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
1400 if (!this._weekdaysParse) {
1401 this._weekdaysParse = [];
1402 this._shortWeekdaysParse = [];
1403 this._minWeekdaysParse = [];
1404
1405 for (i = 0; i < 7; ++i) {
1406 mom = createUTC([2000, 1]).day(i);
1407 this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
1408 this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
1409 this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
1410 }
1411 }
1412
1413 if (strict) {
1414 if (format === 'dddd') {
1415 ii = indexOf.call(this._weekdaysParse, llc);
1416 return ii !== -1 ? ii : null;
1417 } else if (format === 'ddd') {
1418 ii = indexOf.call(this._shortWeekdaysParse, llc);
1419 return ii !== -1 ? ii : null;
1420 } else {
1421 ii = indexOf.call(this._minWeekdaysParse, llc);
1422 return ii !== -1 ? ii : null;
1423 }
1424 } else {
1425 if (format === 'dddd') {
1426 ii = indexOf.call(this._weekdaysParse, llc);
1427 if (ii !== -1) {
1428 return ii;
1429 }
1430 ii = indexOf.call(this._shortWeekdaysParse, llc);
1431 if (ii !== -1) {
1432 return ii;
1433 }
1434 ii = indexOf.call(this._minWeekdaysParse, llc);
1435 return ii !== -1 ? ii : null;
1436 } else if (format === 'ddd') {
1437 ii = indexOf.call(this._shortWeekdaysParse, llc);
1438 if (ii !== -1) {
1439 return ii;
1440 }
1441 ii = indexOf.call(this._weekdaysParse, llc);
1442 if (ii !== -1) {
1443 return ii;
1444 }
1445 ii = indexOf.call(this._minWeekdaysParse, llc);
1446 return ii !== -1 ? ii : null;
1447 } else {
1448 ii = indexOf.call(this._minWeekdaysParse, llc);
1449 if (ii !== -1) {
1450 return ii;
1451 }
1452 ii = indexOf.call(this._weekdaysParse, llc);
1453 if (ii !== -1) {
1454 return ii;
1455 }
1456 ii = indexOf.call(this._shortWeekdaysParse, llc);
1457 return ii !== -1 ? ii : null;
1924 }1458 }
1925 }1459 }
1926 return res;
1927 }1460 }
1928 1461
1929 moment.min = function () {1462 function localeWeekdaysParse(weekdayName, format, strict) {
1930 var args = [].slice.call(arguments, 0);1463 var i, mom, regex;
1931 1464
1932 return pickBy('isBefore', args);1465 if (this._weekdaysParseExact) {
1933 };1466 return handleStrictParse$1.call(this, weekdayName, format, strict);
1467 }
1934 1468
1935 moment.max = function () {1469 if (!this._weekdaysParse) {
1936 var args = [].slice.call(arguments, 0);1470 this._weekdaysParse = [];
1471 this._minWeekdaysParse = [];
1472 this._shortWeekdaysParse = [];
1473 this._fullWeekdaysParse = [];
1474 }
1937 1475
1938 return pickBy('isAfter', args);1476 for (i = 0; i < 7; i++) {
1939 };1477 // make the regex if we don't have it already
1478
1479 mom = createUTC([2000, 1]).day(i);
1480 if (strict && !this._fullWeekdaysParse[i]) {
1481 this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
1482 this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
1483 this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i');
1484 }
1485 if (!this._weekdaysParse[i]) {
1486 regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
1487 this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
1488 }
1489 // test the regex
1490 if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
1491 return i;
1492 } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
1493 return i;
1494 } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
1495 return i;
1496 } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
1497 return i;
1498 }
1499 }
1500 }
1940 1501
1941 // creating with utc1502 // MOMENTS
1942 moment.utc = function (input, format, locale, strict) {
1943 var c;
1944 1503
1945 if (typeof(locale) === 'boolean') {1504 function getSetDayOfWeek(input) {
1946 strict = locale;1505 if (!this.isValid()) {
1947 locale = undefined;1506 return input != null ? this : NaN;
1948 }1507 }
1949 // object construction must be done this way.1508 var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
1950 // https://github.com/moment/moment/issues/14231509 if (input != null) {
1951 c = {};1510 input = parseWeekday(input, this.localeData());
1952 c._isAMomentObject = true;1511 return this.add(input - day, 'd');
1953 c._useUTC = true;1512 } else {
1954 c._isUTC = true;1513 return day;
1955 c._l = locale;1514 }
1956 c._i = input;1515 }
1957 c._f = format;
1958 c._strict = strict;
1959 c._pf = defaultParsingFlags();
1960 1516
1961 return makeMoment(c).utc();1517 function getSetLocaleDayOfWeek(input) {
1962 };1518 if (!this.isValid()) {
1519 return input != null ? this : NaN;
1520 }
1521 var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
1522 return input == null ? weekday : this.add(input - weekday, 'd');
1523 }
1963 1524
1964 // creating with unix timestamp (in seconds)1525 function getSetISODayOfWeek(input) {
1965 moment.unix = function (input) {1526 if (!this.isValid()) {
1966 return moment(input * 1000);1527 return input != null ? this : NaN;
1967 };1528 }
1968 1529
1969 // duration1530 // behaves the same as moment#day except
1970 moment.duration = function (input, key) {1531 // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
1971 var duration = input,1532 // as a setter, sunday should belong to the previous week.
1972 // matching against regexp is expensive, do it on demand
1973 match = null,
1974 sign,
1975 ret,
1976 parseIso,
1977 diffRes;
1978 1533
1979 if (moment.isDuration(input)) {1534 if (input != null) {
1980 duration = {1535 var weekday = parseIsoWeekday(input, this.localeData());
1981 ms: input._milliseconds,1536 return this.day(this.day() % 7 ? weekday : weekday - 7);
1982 d: input._days,1537 } else {
1983 M: input._months1538 return this.day() || 7;
1984 };1539 }
1985 } else if (typeof input === 'number') {1540 }
1986 duration = {};1541
1987 if (key) {1542 var defaultWeekdaysRegex = matchWord;
1988 duration[key] = input;1543 function weekdaysRegex(isStrict) {
1544 if (this._weekdaysParseExact) {
1545 if (!hasOwnProp(this, '_weekdaysRegex')) {
1546 computeWeekdaysParse.call(this);
1547 }
1548 if (isStrict) {
1549 return this._weekdaysStrictRegex;
1989 } else {1550 } else {
1990 duration.milliseconds = input;1551 return this._weekdaysRegex;
1991 }1552 }
1992 } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) {1553 } else {
1993 sign = (match[1] === '-') ? -1 : 1;1554 if (!hasOwnProp(this, '_weekdaysRegex')) {
1994 duration = {1555 this._weekdaysRegex = defaultWeekdaysRegex;
1995 y: 0,1556 }
1996 d: toInt(match[DATE]) * sign,1557 return this._weekdaysStrictRegex && isStrict ?
1997 h: toInt(match[HOUR]) * sign,1558 this._weekdaysStrictRegex : this._weekdaysRegex;
1998 m: toInt(match[MINUTE]) * sign,1559 }
1999 s: toInt(match[SECOND]) * sign,1560 }
2000 ms: toInt(match[MILLISECOND]) * sign
2001 };
2002 } else if (!!(match = isoDurationRegex.exec(input))) {
2003 sign = (match[1] === '-') ? -1 : 1;
2004 parseIso = function (inp) {
2005 // We'd normally use ~~inp for this, but unfortunately it also
2006 // converts floats to ints.
2007 // inp may be undefined, so careful calling replace on it.
2008 var res = inp && parseFloat(inp.replace(',', '.'));
2009 // apply sign while we're at it
2010 return (isNaN(res) ? 0 : res) * sign;
2011 };
2012 duration = {
2013 y: parseIso(match[2]),
2014 M: parseIso(match[3]),
2015 d: parseIso(match[4]),
2016 h: parseIso(match[5]),
2017 m: parseIso(match[6]),
2018 s: parseIso(match[7]),
2019 w: parseIso(match[8])
2020 };
2021 } else if (duration == null) {// checks for null or undefined
2022 duration = {};
2023 } else if (typeof duration === 'object' &&
2024 ('from' in duration || 'to' in duration)) {
2025 diffRes = momentsDifference(moment(duration.from), moment(duration.to));
2026 1561
2027 duration = {};1562 var defaultWeekdaysShortRegex = matchWord;
2028 duration.ms = diffRes.milliseconds;1563 function weekdaysShortRegex(isStrict) {
2029 duration.M = diffRes.months;1564 if (this._weekdaysParseExact) {
1565 if (!hasOwnProp(this, '_weekdaysRegex')) {
1566 computeWeekdaysParse.call(this);
1567 }
1568 if (isStrict) {
1569 return this._weekdaysShortStrictRegex;
1570 } else {
1571 return this._weekdaysShortRegex;
1572 }
1573 } else {
1574 if (!hasOwnProp(this, '_weekdaysShortRegex')) {
1575 this._weekdaysShortRegex = defaultWeekdaysShortRegex;
1576 }
1577 return this._weekdaysShortStrictRegex && isStrict ?
1578 this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
2030 }1579 }
1580 }
2031 1581
2032 ret = new Duration(duration);1582 var defaultWeekdaysMinRegex = matchWord;
1583 function weekdaysMinRegex(isStrict) {
1584 if (this._weekdaysParseExact) {
1585 if (!hasOwnProp(this, '_weekdaysRegex')) {
1586 computeWeekdaysParse.call(this);
1587 }
1588 if (isStrict) {
1589 return this._weekdaysMinStrictRegex;
1590 } else {
1591 return this._weekdaysMinRegex;
1592 }
1593 } else {
1594 if (!hasOwnProp(this, '_weekdaysMinRegex')) {
1595 this._weekdaysMinRegex = defaultWeekdaysMinRegex;
1596 }
1597 return this._weekdaysMinStrictRegex && isStrict ?
1598 this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
1599 }
1600 }
2033 1601
2034 if (moment.isDuration(input) && hasOwnProp(input, '_locale')) {1602
2035 ret._locale = input._locale;1603 function computeWeekdaysParse() {
1604 function cmpLenRev(a, b) {
1605 return b.length - a.length;
2036 }1606 }
2037 1607
2038 return ret;1608 var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
2039 };1609 i, mom, minp, shortp, longp;
1610 for (i = 0; i < 7; i++) {
1611 // make the regex if we don't have it already
1612 mom = createUTC([2000, 1]).day(i);
1613 minp = this.weekdaysMin(mom, '');
1614 shortp = this.weekdaysShort(mom, '');
1615 longp = this.weekdays(mom, '');
1616 minPieces.push(minp);
1617 shortPieces.push(shortp);
1618 longPieces.push(longp);
1619 mixedPieces.push(minp);
1620 mixedPieces.push(shortp);
1621 mixedPieces.push(longp);
1622 }
1623 // Sorting makes sure if one weekday (or abbr) is a prefix of another it
1624 // will match the longer piece.
1625 minPieces.sort(cmpLenRev);
1626 shortPieces.sort(cmpLenRev);
1627 longPieces.sort(cmpLenRev);
1628 mixedPieces.sort(cmpLenRev);
1629 for (i = 0; i < 7; i++) {
1630 shortPieces[i] = regexEscape(shortPieces[i]);
1631 longPieces[i] = regexEscape(longPieces[i]);
1632 mixedPieces[i] = regexEscape(mixedPieces[i]);
1633 }
2040 1634
2041 // version number1635 this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
2042 moment.version = VERSION;1636 this._weekdaysShortRegex = this._weekdaysRegex;
1637 this._weekdaysMinRegex = this._weekdaysRegex;
2043 1638
2044 // default format1639 this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
2045 moment.defaultFormat = isoFormat;1640 this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
1641 this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
1642 }
2046 1643
2047 // constant that refers to the ISO standard1644 // FORMATTING
2048 moment.ISO_8601 = function () {};
2049 1645
2050 // Plugins that add properties should also add the key here (null value),1646 function hFormat() {
2051 // so we can properly clone ourselves.1647 return this.hours() % 12 || 12;
2052 moment.momentProperties = momentProperties;1648 }
2053 1649
2054 // This function will be called whenever a moment is mutated.1650 function kFormat() {
2055 // It is intended to keep the offset in sync with the timezone.1651 return this.hours() || 24;
2056 moment.updateOffset = function () {};1652 }
2057 1653
2058 // This function allows you to set a threshold for relative time strings1654 addFormatToken('H', ['HH', 2], 0, 'hour');
2059 moment.relativeTimeThreshold = function (threshold, limit) {1655 addFormatToken('h', ['hh', 2], 0, hFormat);
2060 if (relativeTimeThresholds[threshold] === undefined) {1656 addFormatToken('k', ['kk', 2], 0, kFormat);
2061 return false;1657
2062 }1658 addFormatToken('hmm', 0, 0, function () {
2063 if (limit === undefined) {1659 return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
2064 return relativeTimeThresholds[threshold];1660 });
1661
1662 addFormatToken('hmmss', 0, 0, function () {
1663 return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
1664 zeroFill(this.seconds(), 2);
1665 });
1666
1667 addFormatToken('Hmm', 0, 0, function () {
1668 return '' + this.hours() + zeroFill(this.minutes(), 2);
1669 });
1670
1671 addFormatToken('Hmmss', 0, 0, function () {
1672 return '' + this.hours() + zeroFill(this.minutes(), 2) +
1673 zeroFill(this.seconds(), 2);
1674 });
1675
1676 function meridiem(token, lowercase) {
1677 addFormatToken(token, 0, 0, function () {
1678 return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
1679 });
1680 }
1681
1682 meridiem('a', true);
1683 meridiem('A', false);
1684
1685 // ALIASES
1686
1687 addUnitAlias('hour', 'h');
1688
1689 // PRIORITY
1690 addUnitPriority('hour', 13);
1691
1692 // PARSING
1693
1694 function matchMeridiem(isStrict, locale) {
1695 return locale._meridiemParse;
1696 }
1697
1698 addRegexToken('a', matchMeridiem);
1699 addRegexToken('A', matchMeridiem);
1700 addRegexToken('H', match1to2);
1701 addRegexToken('h', match1to2);
1702 addRegexToken('k', match1to2);
1703 addRegexToken('HH', match1to2, match2);
1704 addRegexToken('hh', match1to2, match2);
1705 addRegexToken('kk', match1to2, match2);
1706
1707 addRegexToken('hmm', match3to4);
1708 addRegexToken('hmmss', match5to6);
1709 addRegexToken('Hmm', match3to4);
1710 addRegexToken('Hmmss', match5to6);
1711
1712 addParseToken(['H', 'HH'], HOUR);
1713 addParseToken(['k', 'kk'], function (input, array, config) {
1714 var kInput = toInt(input);
1715 array[HOUR] = kInput === 24 ? 0 : kInput;
1716 });
1717 addParseToken(['a', 'A'], function (input, array, config) {
1718 config._isPm = config._locale.isPM(input);
1719 config._meridiem = input;
1720 });
1721 addParseToken(['h', 'hh'], function (input, array, config) {
1722 array[HOUR] = toInt(input);
1723 getParsingFlags(config).bigHour = true;
1724 });
1725 addParseToken('hmm', function (input, array, config) {
1726 var pos = input.length - 2;
1727 array[HOUR] = toInt(input.substr(0, pos));
1728 array[MINUTE] = toInt(input.substr(pos));
1729 getParsingFlags(config).bigHour = true;
1730 });
1731 addParseToken('hmmss', function (input, array, config) {
1732 var pos1 = input.length - 4;
1733 var pos2 = input.length - 2;
1734 array[HOUR] = toInt(input.substr(0, pos1));
1735 array[MINUTE] = toInt(input.substr(pos1, 2));
1736 array[SECOND] = toInt(input.substr(pos2));
1737 getParsingFlags(config).bigHour = true;
1738 });
1739 addParseToken('Hmm', function (input, array, config) {
1740 var pos = input.length - 2;
1741 array[HOUR] = toInt(input.substr(0, pos));
1742 array[MINUTE] = toInt(input.substr(pos));
1743 });
1744 addParseToken('Hmmss', function (input, array, config) {
1745 var pos1 = input.length - 4;
1746 var pos2 = input.length - 2;
1747 array[HOUR] = toInt(input.substr(0, pos1));
1748 array[MINUTE] = toInt(input.substr(pos1, 2));
1749 array[SECOND] = toInt(input.substr(pos2));
1750 });
1751
1752 // LOCALES
1753
1754 function localeIsPM(input) {
1755 // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
1756 // Using charAt should be more compatible.
1757 return ((input + '').toLowerCase().charAt(0) === 'p');
1758 }
1759
1760 var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
1761 function localeMeridiem(hours, minutes, isLower) {
1762 if (hours > 11) {
1763 return isLower ? 'pm' : 'PM';
1764 } else {
1765 return isLower ? 'am' : 'AM';
2065 }1766 }
2066 relativeTimeThresholds[threshold] = limit;1767 }
2067 return true;1768
1769
1770 // MOMENTS
1771
1772 // Setting the hour should keep the time, because the user explicitly
1773 // specified which hour he wants. So trying to maintain the same hour (in
1774 // a new timezone) makes sense. Adding/subtracting hours does not follow
1775 // this rule.
1776 var getSetHour = makeGetSet('Hours', true);
1777
1778 // months
1779 // week
1780 // weekdays
1781 // meridiem
1782 var baseConfig = {
1783 calendar: defaultCalendar,
1784 longDateFormat: defaultLongDateFormat,
1785 invalidDate: defaultInvalidDate,
1786 ordinal: defaultOrdinal,
1787 dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
1788 relativeTime: defaultRelativeTime,
1789
1790 months: defaultLocaleMonths,
1791 monthsShort: defaultLocaleMonthsShort,
1792
1793 week: defaultLocaleWeek,
1794
1795 weekdays: defaultLocaleWeekdays,
1796 weekdaysMin: defaultLocaleWeekdaysMin,
1797 weekdaysShort: defaultLocaleWeekdaysShort,
1798
1799 meridiemParse: defaultLocaleMeridiemParse
2068 };1800 };
2069 1801
2070 moment.lang = deprecate(1802 // internal storage for locale config files
2071 'moment.lang is deprecated. Use moment.locale instead.',1803 var locales = {};
2072 function (key, value) {1804 var localeFamilies = {};
2073 return moment.locale(key, value);1805 var globalLocale;
1806
1807 function normalizeLocale(key) {
1808 return key ? key.toLowerCase().replace('_', '-') : key;
1809 }
1810
1811 // pick the locale from the array
1812 // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
1813 // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
1814 function chooseLocale(names) {
1815 var i = 0, j, next, locale, split;
1816
1817 while (i < names.length) {
1818 split = normalizeLocale(names[i]).split('-');
1819 j = split.length;
1820 next = normalizeLocale(names[i + 1]);
1821 next = next ? next.split('-') : null;
1822 while (j > 0) {
1823 locale = loadLocale(split.slice(0, j).join('-'));
1824 if (locale) {
1825 return locale;
1826 }
1827 if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
1828 //the next array item is better than a shallower substring of this one
1829 break;
1830 }
1831 j--;
1832 }
1833 i++;
1834 }
1835 return null;
1836 }
1837
1838 function loadLocale(name) {
1839 var oldLocale = null;
1840 // TODO: Find a better way to register and load all the locales in Node
1841 if (!locales[name] && (typeof module !== 'undefined') &&
1842 module && module.exports) {
1843 try {
1844 oldLocale = globalLocale._abbr;
1845 var aliasedRequire = require;
1846 aliasedRequire('./locale/' + name);
1847 getSetGlobalLocale(oldLocale);
1848 } catch (e) { }
2074 }1849 }
2075 );1850 return locales[name];
1851 }
2076 1852
2077 // This function will load locale and then set the global locale. If1853 // This function will load locale and then set the global locale. If
2078 // no arguments are passed in, it will simply return the current global1854 // no arguments are passed in, it will simply return the current global
2079 // locale key.1855 // locale key.
2080 moment.locale = function (key, values) {1856 function getSetGlobalLocale(key, values) {
2081 var data;1857 var data;
2082 if (key) {1858 if (key) {
2083 if (typeof(values) !== 'undefined') {1859 if (isUndefined(values)) {
2084 data = moment.defineLocale(key, values);1860 data = getLocale(key);
2085 }1861 }
2086 else {1862 else {
2087 data = moment.localeData(key);1863 data = defineLocale(key, values);
2088 }1864 }
2089 1865
2090 if (data) {1866 if (data) {
2091 moment.duration._locale = moment._locale = data;1867 // moment.duration._locale = moment._locale = data;
1868 globalLocale = data;
2092 }1869 }
2093 }1870 }
2094 1871
2095 return moment._locale._abbr;1872 return globalLocale._abbr;
2096 };1873 }
2097 1874
2098 moment.defineLocale = function (name, values) {1875 function defineLocale(name, config) {
2099 if (values !== null) {1876 if (config !== null) {
2100 values.abbr = name;1877 var parentConfig = baseConfig;
2101 if (!locales[name]) {1878 config.abbr = name;
2102 locales[name] = new Locale();1879 if (locales[name] != null) {
2103 }1880 deprecateSimple('defineLocaleOverride',
2104 locales[name].set(values);1881 'use moment.updateLocale(localeName, config) to change ' +
1882 'an existing locale. moment.defineLocale(localeName, ' +
1883 'config) should only be used for creating a new locale ' +
1884 'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
1885 parentConfig = locales[name]._config;
1886 } else if (config.parentLocale != null) {
1887 if (locales[config.parentLocale] != null) {
1888 parentConfig = locales[config.parentLocale]._config;
1889 } else {
1890 if (!localeFamilies[config.parentLocale]) {
1891 localeFamilies[config.parentLocale] = [];
1892 }
1893 localeFamilies[config.parentLocale].push({
1894 name: name,
1895 config: config
1896 });
1897 return null;
1898 }
1899 }
1900 locales[name] = new Locale(mergeConfigs(parentConfig, config));
1901
1902 if (localeFamilies[name]) {
1903 localeFamilies[name].forEach(function (x) {
1904 defineLocale(x.name, x.config);
1905 });
1906 }
1907
1908 // backwards compat for now: also set the locale
1909 // make sure we set the locale AFTER all child locales have been
1910 // created, so we won't end up with the child locale set.
1911 getSetGlobalLocale(name);
2105 1912
2106 // backwards compat for now: also set the locale
2107 moment.locale(name);
2108 1913
2109 return locales[name];1914 return locales[name];
2110 } else {1915 } else {
@@ -2112,17 +1917,38 @@ · 1 unmodified line
2112 delete locales[name];1917 delete locales[name];
2113 return null;1918 return null;
2114 }1919 }
2115 };1920 }
2116 1921
2117 moment.langData = deprecate(1922 function updateLocale(name, config) {
2118 'moment.langData is deprecated. Use moment.localeData instead.',1923 if (config != null) {
2119 function (key) {1924 var locale, tmpLocale, parentConfig = baseConfig;
2120 return moment.localeData(key);1925 // MERGE
1926 tmpLocale = loadLocale(name);
1927 if (tmpLocale != null) {
1928 parentConfig = tmpLocale._config;
1929 }
1930 config = mergeConfigs(parentConfig, config);
1931 locale = new Locale(config);
1932 locale.parentLocale = locales[name];
1933 locales[name] = locale;
1934
1935 // backwards compat for now: also set the locale
1936 getSetGlobalLocale(name);
1937 } else {
1938 // pass null for config to unupdate, useful for tests
1939 if (locales[name] != null) {
1940 if (locales[name].parentLocale != null) {
1941 locales[name] = locales[name].parentLocale;
1942 } else if (locales[name] != null) {
1943 delete locales[name];
1944 }
1945 }
2121 }1946 }
2122 );1947 return locales[name];
1948 }
2123 1949
2124 // returns locale data1950 // returns locale data
2125 moment.localeData = function (key) {1951 function getLocale(key) {
2126 var locale;1952 var locale;
2127 1953
2128 if (key && key._locale && key._locale._abbr) {1954 if (key && key._locale && key._locale._abbr) {
@@ -2130,7 +1956,7 @@ · 1 unmodified line
2130 }1956 }
2131 1957
2132 if (!key) {1958 if (!key) {
2133 return moment._locale;1959 return globalLocale;
2134 }1960 }
2135 1961
2136 if (!isArray(key)) {1962 if (!isArray(key)) {
@@ -2143,901 +1969,2568 @@ · 6 unmodified lines
2143 }1969 }
2144 1970
2145 return chooseLocale(key);1971 return chooseLocale(key);
1972 }
1973
1974 function listLocales() {
1975 return keys(locales);
1976 }
1977
1978 function checkOverflow(m) {
1979 var overflow;
1980 var a = m._a;
1981
1982 if (a && getParsingFlags(m).overflow === -2) {
1983 overflow =
1984 a[MONTH] < 0 || a[MONTH] > 11 ? MONTH :
1985 a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
1986 a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
1987 a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE :
1988 a[SECOND] < 0 || a[SECOND] > 59 ? SECOND :
1989 a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
1990 -1;
1991
1992 if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
1993 overflow = DATE;
1994 }
1995 if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
1996 overflow = WEEK;
1997 }
1998 if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
1999 overflow = WEEKDAY;
2000 }
2001
2002 getParsingFlags(m).overflow = overflow;
2003 }
2004
2005 return m;
2006 }
2007
2008 // Pick the first defined of two or three arguments.
2009 function defaults(a, b, c) {
2010 if (a != null) {
2011 return a;
2012 }
2013 if (b != null) {
2014 return b;
2015 }
2016 return c;
2017 }
2018
2019 function currentDateArray(config) {
2020 // hooks is actually the exported moment object
2021 var nowValue = new Date(hooks.now());
2022 if (config._useUTC) {
2023 return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
2024 }
2025 return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
2026 }
2027
2028 // convert an array to a date.
2029 // the array should mirror the parameters below
2030 // note: all values past the year are optional and will default to the lowest possible value.
2031 // [year, month, day , hour, minute, second, millisecond]
2032 function configFromArray(config) {
2033 var i, date, input = [], currentDate, expectedWeekday, yearToUse;
2034
2035 if (config._d) {
2036 return;
2037 }
2038
2039 currentDate = currentDateArray(config);
2040
2041 //compute day of the year from weeks and weekdays
2042 if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
2043 dayOfYearFromWeekInfo(config);
2044 }
2045
2046 //if the day of the year is set, figure out what it is
2047 if (config._dayOfYear != null) {
2048 yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
2049
2050 if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
2051 getParsingFlags(config)._overflowDayOfYear = true;
2052 }
2053
2054 date = createUTCDate(yearToUse, 0, config._dayOfYear);
2055 config._a[MONTH] = date.getUTCMonth();
2056 config._a[DATE] = date.getUTCDate();
2057 }
2058
2059 // Default to current date.
2060 // * if no year, month, day of month are given, default to today
2061 // * if day of month is given, default month and year
2062 // * if month is given, default only year
2063 // * if year is given, don't default anything
2064 for (i = 0; i < 3 && config._a[i] == null; ++i) {
2065 config._a[i] = input[i] = currentDate[i];
2066 }
2067
2068 // Zero out whatever was not defaulted, including time
2069 for (; i < 7; i++) {
2070 config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
2071 }
2072
2073 // Check for 24:00:00.000
2074 if (config._a[HOUR] === 24 &&
2075 config._a[MINUTE] === 0 &&
2076 config._a[SECOND] === 0 &&
2077 config._a[MILLISECOND] === 0) {
2078 config._nextDay = true;
2079 config._a[HOUR] = 0;
2080 }
2081
2082 config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
2083 expectedWeekday = config._useUTC ? config._d.getUTCDay() : config._d.getDay();
2084
2085 // Apply timezone offset from input. The actual utcOffset can be changed
2086 // with parseZone.
2087 if (config._tzm != null) {
2088 config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
2089 }
2090
2091 if (config._nextDay) {
2092 config._a[HOUR] = 24;
2093 }
2094
2095 // check for mismatching day of week
2096 if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== expectedWeekday) {
2097 getParsingFlags(config).weekdayMismatch = true;
2098 }
2099 }
2100
2101 function dayOfYearFromWeekInfo(config) {
2102 var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
2103
2104 w = config._w;
2105 if (w.GG != null || w.W != null || w.E != null) {
2106 dow = 1;
2107 doy = 4;
2108
2109 // TODO: We need to take the current isoWeekYear, but that depends on
2110 // how we interpret now (local, utc, fixed offset). So create
2111 // a now version of current config (take local/utc/offset flags, and
2112 // create now).
2113 weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
2114 week = defaults(w.W, 1);
2115 weekday = defaults(w.E, 1);
2116 if (weekday < 1 || weekday > 7) {
2117 weekdayOverflow = true;
2118 }
2119 } else {
2120 dow = config._locale._week.dow;
2121 doy = config._locale._week.doy;
2122
2123 var curWeek = weekOfYear(createLocal(), dow, doy);
2124
2125 weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);
2126
2127 // Default to current week.
2128 week = defaults(w.w, curWeek.week);
2129
2130 if (w.d != null) {
2131 // weekday -- low day numbers are considered next week
2132 weekday = w.d;
2133 if (weekday < 0 || weekday > 6) {
2134 weekdayOverflow = true;
2135 }
2136 } else if (w.e != null) {
2137 // local weekday -- counting starts from begining of week
2138 weekday = w.e + dow;
2139 if (w.e < 0 || w.e > 6) {
2140 weekdayOverflow = true;
2141 }
2142 } else {
2143 // default to begining of week
2144 weekday = dow;
2145 }
2146 }
2147 if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
2148 getParsingFlags(config)._overflowWeeks = true;
2149 } else if (weekdayOverflow != null) {
2150 getParsingFlags(config)._overflowWeekday = true;
2151 } else {
2152 temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
2153 config._a[YEAR] = temp.year;
2154 config._dayOfYear = temp.dayOfYear;
2155 }
2156 }
2157
2158 // iso 8601 regex
2159 // 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)
2160 var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
2161 var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
2162
2163 var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
2164
2165 var isoDates = [
2166 ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
2167 ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
2168 ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
2169 ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
2170 ['YYYY-DDD', /\d{4}-\d{3}/],
2171 ['YYYY-MM', /\d{4}-\d\d/, false],
2172 ['YYYYYYMMDD', /[+-]\d{10}/],
2173 ['YYYYMMDD', /\d{8}/],
2174 // YYYYMM is NOT allowed by the standard
2175 ['GGGG[W]WWE', /\d{4}W\d{3}/],
2176 ['GGGG[W]WW', /\d{4}W\d{2}/, false],
2177 ['YYYYDDD', /\d{7}/]
2178 ];
2179
2180 // iso time formats and regexes
2181 var isoTimes = [
2182 ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
2183 ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
2184 ['HH:mm:ss', /\d\d:\d\d:\d\d/],
2185 ['HH:mm', /\d\d:\d\d/],
2186 ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
2187 ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
2188 ['HHmmss', /\d\d\d\d\d\d/],
2189 ['HHmm', /\d\d\d\d/],
2190 ['HH', /\d\d/]
2191 ];
2192
2193 var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
2194
2195 // date from iso format
2196 function configFromISO(config) {
2197 var i, l,
2198 string = config._i,
2199 match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
2200 allowTime, dateFormat, timeFormat, tzFormat;
2201
2202 if (match) {
2203 getParsingFlags(config).iso = true;
2204
2205 for (i = 0, l = isoDates.length; i < l; i++) {
2206 if (isoDates[i][1].exec(match[1])) {
2207 dateFormat = isoDates[i][0];
2208 allowTime = isoDates[i][2] !== false;
2209 break;
2210 }
2211 }
2212 if (dateFormat == null) {
2213 config._isValid = false;
2214 return;
2215 }
2216 if (match[3]) {
2217 for (i = 0, l = isoTimes.length; i < l; i++) {
2218 if (isoTimes[i][1].exec(match[3])) {
2219 // match[2] should be 'T' or space
2220 timeFormat = (match[2] || ' ') + isoTimes[i][0];
2221 break;
2222 }
2223 }
2224 if (timeFormat == null) {
2225 config._isValid = false;
2226 return;
2227 }
2228 }
2229 if (!allowTime && timeFormat != null) {
2230 config._isValid = false;
2231 return;
2232 }
2233 if (match[4]) {
2234 if (tzRegex.exec(match[4])) {
2235 tzFormat = 'Z';
2236 } else {
2237 config._isValid = false;
2238 return;
2239 }
2240 }
2241 config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
2242 configFromStringAndFormat(config);
2243 } else {
2244 config._isValid = false;
2245 }
2246 }
2247
2248 // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
2249 var rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/;
2250
2251 function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
2252 var result = [
2253 untruncateYear(yearStr),
2254 defaultLocaleMonthsShort.indexOf(monthStr),
2255 parseInt(dayStr, 10),
2256 parseInt(hourStr, 10),
2257 parseInt(minuteStr, 10)
2258 ];
2259
2260 if (secondStr) {
2261 result.push(parseInt(secondStr, 10));
2262 }
2263
2264 return result;
2265 }
2266
2267 function untruncateYear(yearStr) {
2268 var year = parseInt(yearStr, 10);
2269 if (year <= 49) {
2270 return 2000 + year;
2271 } else if (year <= 999) {
2272 return 1900 + year;
2273 }
2274 return year;
2275 }
2276
2277 function preprocessRFC2822(s) {
2278 // Remove comments and folding whitespace and replace multiple-spaces with a single space
2279 return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').trim();
2280 }
2281
2282 function checkWeekday(weekdayStr, parsedInput, config) {
2283 if (weekdayStr) {
2284 // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
2285 var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
2286 weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay();
2287 if (weekdayProvided !== weekdayActual) {
2288 getParsingFlags(config).weekdayMismatch = true;
2289 config._isValid = false;
2290 return false;
2291 }
2292 }
2293 return true;
2294 }
2295
2296 var obsOffsets = {
2297 UT: 0,
2298 GMT: 0,
2299 EDT: -4 * 60,
2300 EST: -5 * 60,
2301 CDT: -5 * 60,
2302 CST: -6 * 60,
2303 MDT: -6 * 60,
2304 MST: -7 * 60,
2305 PDT: -7 * 60,
2306 PST: -8 * 60
2146 };2307 };
2147 2308
2148 // compare moment object2309 function calculateOffset(obsOffset, militaryOffset, numOffset) {
2149 moment.isMoment = function (obj) {2310 if (obsOffset) {
2150 return obj instanceof Moment ||2311 return obsOffsets[obsOffset];
2151 (obj != null && hasOwnProp(obj, '_isAMomentObject'));2312 } else if (militaryOffset) {
2152 };2313 // the only allowed military tz is Z
2314 return 0;
2315 } else {
2316 var hm = parseInt(numOffset, 10);
2317 var m = hm % 100, h = (hm - m) / 100;
2318 return h * 60 + m;
2319 }
2320 }
2321
2322 // date and time from ref 2822 format
2323 function configFromRFC2822(config) {
2324 var match = rfc2822.exec(preprocessRFC2822(config._i));
2325 if (match) {
2326 var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]);
2327 if (!checkWeekday(match[1], parsedArray, config)) {
2328 return;
2329 }
2330
2331 config._a = parsedArray;
2332 config._tzm = calculateOffset(match[8], match[9], match[10]);
2333
2334 config._d = createUTCDate.apply(null, config._a);
2335 config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
2336
2337 getParsingFlags(config).rfc2822 = true;
2338 } else {
2339 config._isValid = false;
2340 }
2341 }
2342
2343 // date from iso format or fallback
2344 function configFromString(config) {
2345 var matched = aspNetJsonRegex.exec(config._i);
2346
2347 if (matched !== null) {
2348 config._d = new Date(+matched[1]);
2349 return;
2350 }
2351
2352 configFromISO(config);
2353 if (config._isValid === false) {
2354 delete config._isValid;
2355 } else {
2356 return;
2357 }
2358
2359 configFromRFC2822(config);
2360 if (config._isValid === false) {
2361 delete config._isValid;
2362 } else {
2363 return;
2364 }
2365
2366 // Final attempt, use Input Fallback
2367 hooks.createFromInputFallback(config);
2368 }
2369
2370 hooks.createFromInputFallback = deprecate(
2371 'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
2372 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
2373 'discouraged and will be removed in an upcoming major release. Please refer to ' +
2374 'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
2375 function (config) {
2376 config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
2377 }
2378 );
2379
2380 // constant that refers to the ISO standard
2381 hooks.ISO_8601 = function () { };
2382
2383 // constant that refers to the RFC 2822 form
2384 hooks.RFC_2822 = function () { };
2385
2386 // date from string and format string
2387 function configFromStringAndFormat(config) {
2388 // TODO: Move this to another part of the creation flow to prevent circular deps
2389 if (config._f === hooks.ISO_8601) {
2390 configFromISO(config);
2391 return;
2392 }
2393 if (config._f === hooks.RFC_2822) {
2394 configFromRFC2822(config);
2395 return;
2396 }
2397 config._a = [];
2398 getParsingFlags(config).empty = true;
2399
2400 // This array is used to make a Date, either with `new Date` or `Date.UTC`
2401 var string = '' + config._i,
2402 i, parsedInput, tokens, token, skipped,
2403 stringLength = string.length,
2404 totalParsedInputLength = 0;
2405
2406 tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
2407
2408 for (i = 0; i < tokens.length; i++) {
2409 token = tokens[i];
2410 parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
2411 // console.log('token', token, 'parsedInput', parsedInput,
2412 // 'regex', getParseRegexForToken(token, config));
2413 if (parsedInput) {
2414 skipped = string.substr(0, string.indexOf(parsedInput));
2415 if (skipped.length > 0) {
2416 getParsingFlags(config).unusedInput.push(skipped);
2417 }
2418 string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
2419 totalParsedInputLength += parsedInput.length;
2420 }
2421 // don't parse if it's not a known token
2422 if (formatTokenFunctions[token]) {
2423 if (parsedInput) {
2424 getParsingFlags(config).empty = false;
2425 }
2426 else {
2427 getParsingFlags(config).unusedTokens.push(token);
2428 }
2429 addTimeToArrayFromToken(token, parsedInput, config);
2430 }
2431 else if (config._strict && !parsedInput) {
2432 getParsingFlags(config).unusedTokens.push(token);
2433 }
2434 }
2435
2436 // add remaining unparsed input length to the string
2437 getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
2438 if (string.length > 0) {
2439 getParsingFlags(config).unusedInput.push(string);
2440 }
2441
2442 // clear _12h flag if hour is <= 12
2443 if (config._a[HOUR] <= 12 &&
2444 getParsingFlags(config).bigHour === true &&
2445 config._a[HOUR] > 0) {
2446 getParsingFlags(config).bigHour = undefined;
2447 }
2448
2449 getParsingFlags(config).parsedDateParts = config._a.slice(0);
2450 getParsingFlags(config).meridiem = config._meridiem;
2451 // handle meridiem
2452 config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
2453
2454 configFromArray(config);
2455 checkOverflow(config);
2456 }
2457
2458
2459 function meridiemFixWrap(locale, hour, meridiem) {
2460 var isPm;
2461
2462 if (meridiem == null) {
2463 // nothing to do
2464 return hour;
2465 }
2466 if (locale.meridiemHour != null) {
2467 return locale.meridiemHour(hour, meridiem);
2468 } else if (locale.isPM != null) {
2469 // Fallback
2470 isPm = locale.isPM(meridiem);
2471 if (isPm && hour < 12) {
2472 hour += 12;
2473 }
2474 if (!isPm && hour === 12) {
2475 hour = 0;
2476 }
2477 return hour;
2478 } else {
2479 // this is not supposed to happen
2480 return hour;
2481 }
2482 }
2483
2484 // date from string and array of format strings
2485 function configFromStringAndArray(config) {
2486 var tempConfig,
2487 bestMoment,
2488
2489 scoreToBeat,
2490 i,
2491 currentScore;
2492
2493 if (config._f.length === 0) {
2494 getParsingFlags(config).invalidFormat = true;
2495 config._d = new Date(NaN);
2496 return;
2497 }
2498
2499 for (i = 0; i < config._f.length; i++) {
2500 currentScore = 0;
2501 tempConfig = copyConfig({}, config);
2502 if (config._useUTC != null) {
2503 tempConfig._useUTC = config._useUTC;
2504 }
2505 tempConfig._f = config._f[i];
2506 configFromStringAndFormat(tempConfig);
2507
2508 if (!isValid(tempConfig)) {
2509 continue;
2510 }
2511
2512 // if there is any input that was not parsed add a penalty for that format
2513 currentScore += getParsingFlags(tempConfig).charsLeftOver;
2514
2515 //or tokens
2516 currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
2517
2518 getParsingFlags(tempConfig).score = currentScore;
2519
2520 if (scoreToBeat == null || currentScore < scoreToBeat) {
2521 scoreToBeat = currentScore;
2522 bestMoment = tempConfig;
2523 }
2524 }
2525
2526 extend(config, bestMoment || tempConfig);
2527 }
2528
2529 function configFromObject(config) {
2530 if (config._d) {
2531 return;
2532 }
2533
2534 var i = normalizeObjectUnits(config._i);
2535 config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
2536 return obj && parseInt(obj, 10);
2537 });
2538
2539 configFromArray(config);
2540 }
2541
2542 function createFromConfig(config) {
2543 var res = new Moment(checkOverflow(prepareConfig(config)));
2544 if (res._nextDay) {
2545 // Adding is smart enough around DST
2546 res.add(1, 'd');
2547 res._nextDay = undefined;
2548 }
2549
2550 return res;
2551 }
2552
2553 function prepareConfig(config) {
2554 var input = config._i,
2555 format = config._f;
2556
2557 config._locale = config._locale || getLocale(config._l);
2558
2559 if (input === null || (format === undefined && input === '')) {
2560 return createInvalid({ nullInput: true });
2561 }
2562
2563 if (typeof input === 'string') {
2564 config._i = input = config._locale.preparse(input);
2565 }
2566
2567 if (isMoment(input)) {
2568 return new Moment(checkOverflow(input));
2569 } else if (isDate(input)) {
2570 config._d = input;
2571 } else if (isArray(format)) {
2572 configFromStringAndArray(config);
2573 } else if (format) {
2574 configFromStringAndFormat(config);
2575 } else {
2576 configFromInput(config);
2577 }
2578
2579 if (!isValid(config)) {
2580 config._d = null;
2581 }
2582
2583 return config;
2584 }
2585
2586 function configFromInput(config) {
2587 var input = config._i;
2588 if (isUndefined(input)) {
2589 config._d = new Date(hooks.now());
2590 } else if (isDate(input)) {
2591 config._d = new Date(input.valueOf());
2592 } else if (typeof input === 'string') {
2593 configFromString(config);
2594 } else if (isArray(input)) {
2595 config._a = map(input.slice(0), function (obj) {
2596 return parseInt(obj, 10);
2597 });
2598 configFromArray(config);
2599 } else if (isObject(input)) {
2600 configFromObject(config);
2601 } else if (isNumber(input)) {
2602 // from milliseconds
2603 config._d = new Date(input);
2604 } else {
2605 hooks.createFromInputFallback(config);
2606 }
2607 }
2608
2609 function createLocalOrUTC(input, format, locale, strict, isUTC) {
2610 var c = {};
2611
2612 if (locale === true || locale === false) {
2613 strict = locale;
2614 locale = undefined;
2615 }
2616
2617 if ((isObject(input) && isObjectEmpty(input)) ||
2618 (isArray(input) && input.length === 0)) {
2619 input = undefined;
2620 }
2621 // object construction must be done this way.
2622 // https://github.com/moment/moment/issues/1423
2623 c._isAMomentObject = true;
2624 c._useUTC = c._isUTC = isUTC;
2625 c._l = locale;
2626 c._i = input;
2627 c._f = format;
2628 c._strict = strict;
2629
2630 return createFromConfig(c);
2631 }
2632
2633 function createLocal(input, format, locale, strict) {
2634 return createLocalOrUTC(input, format, locale, strict, false);
2635 }
2636
2637 var prototypeMin = deprecate(
2638 'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
2639 function () {
2640 var other = createLocal.apply(null, arguments);
2641 if (this.isValid() && other.isValid()) {
2642 return other < this ? this : other;
2643 } else {
2644 return createInvalid();
2645 }
2646 }
2647 );
2648
2649 var prototypeMax = deprecate(
2650 'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
2651 function () {
2652 var other = createLocal.apply(null, arguments);
2653 if (this.isValid() && other.isValid()) {
2654 return other > this ? this : other;
2655 } else {
2656 return createInvalid();
2657 }
2658 }
2659 );
2660
2661 // Pick a moment m from moments so that m[fn](other) is true for all
2662 // other. This relies on the function fn to be transitive.
2663 //
2664 // moments should either be an array of moment objects or an array, whose
2665 // first element is an array of moment objects.
2666 function pickBy(fn, moments) {
2667 var res, i;
2668 if (moments.length === 1 && isArray(moments[0])) {
2669 moments = moments[0];
2670 }
2671 if (!moments.length) {
2672 return createLocal();
2673 }
2674 res = moments[0];
2675 for (i = 1; i < moments.length; ++i) {
2676 if (!moments[i].isValid() || moments[i][fn](res)) {
2677 res = moments[i];
2678 }
2679 }
2680 return res;
2681 }
2682
2683 // TODO: Use [].sort instead?
2684 function min() {
2685 var args = [].slice.call(arguments, 0);
2686
2687 return pickBy('isBefore', args);
2688 }
2689
2690 function max() {
2691 var args = [].slice.call(arguments, 0);
2692
2693 return pickBy('isAfter', args);
2694 }
2695
2696 var now = function () {
2697 return Date.now ? Date.now() : +(new Date());
2698 };
2699
2700 var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];
2701
2702 function isDurationValid(m) {
2703 for (var key in m) {
2704 if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
2705 return false;
2706 }
2707 }
2708
2709 var unitHasDecimal = false;
2710 for (var i = 0; i < ordering.length; ++i) {
2711 if (m[ordering[i]]) {
2712 if (unitHasDecimal) {
2713 return false; // only allow non-integers for smallest unit
2714 }
2715 if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
2716 unitHasDecimal = true;
2717 }
2718 }
2719 }
2720
2721 return true;
2722 }
2723
2724 function isValid$1() {
2725 return this._isValid;
2726 }
2727
2728 function createInvalid$1() {
2729 return createDuration(NaN);
2730 }
2731
2732 function Duration(duration) {
2733 var normalizedInput = normalizeObjectUnits(duration),
2734 years = normalizedInput.year || 0,
2735 quarters = normalizedInput.quarter || 0,
2736 months = normalizedInput.month || 0,
2737 weeks = normalizedInput.week || 0,
2738 days = normalizedInput.day || 0,
2739 hours = normalizedInput.hour || 0,
2740 minutes = normalizedInput.minute || 0,
2741 seconds = normalizedInput.second || 0,
2742 milliseconds = normalizedInput.millisecond || 0;
2743
2744 this._isValid = isDurationValid(normalizedInput);
2745
2746 // representation for dateAddRemove
2747 this._milliseconds = +milliseconds +
2748 seconds * 1e3 + // 1000
2749 minutes * 6e4 + // 1000 * 60
2750 hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
2751 // Because of dateAddRemove treats 24 hours as different from a
2752 // day when working around DST, we need to store them separately
2753 this._days = +days +
2754 weeks * 7;
2755 // It is impossible to translate months into days without knowing
2756 // which months you are are talking about, so we have to store
2757 // it separately.
2758 this._months = +months +
2759 quarters * 3 +
2760 years * 12;
2761
2762 this._data = {};
2763
2764 this._locale = getLocale();
2765
2766 this._bubble();
2767 }
2768
2769 function isDuration(obj) {
2770 return obj instanceof Duration;
2771 }
2772
2773 function absRound(number) {
2774 if (number < 0) {
2775 return Math.round(-1 * number) * -1;
2776 } else {
2777 return Math.round(number);
2778 }
2779 }
2780
2781 // FORMATTING
2782
2783 function offset(token, separator) {
2784 addFormatToken(token, 0, 0, function () {
2785 var offset = this.utcOffset();
2786 var sign = '+';
2787 if (offset < 0) {
2788 offset = -offset;
2789 sign = '-';
2790 }
2791 return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
2792 });
2793 }
2794
2795 offset('Z', ':');
2796 offset('ZZ', '');
2797
2798 // PARSING
2799
2800 addRegexToken('Z', matchShortOffset);
2801 addRegexToken('ZZ', matchShortOffset);
2802 addParseToken(['Z', 'ZZ'], function (input, array, config) {
2803 config._useUTC = true;
2804 config._tzm = offsetFromString(matchShortOffset, input);
2805 });
2806
2807 // HELPERS
2808
2809 // timezone chunker
2810 // '+10:00' > ['10', '00']
2811 // '-1530' > ['-15', '30']
2812 var chunkOffset = /([\+\-]|\d\d)/gi;
2813
2814 function offsetFromString(matcher, string) {
2815 var matches = (string || '').match(matcher);
2816
2817 if (matches === null) {
2818 return null;
2819 }
2820
2821 var chunk = matches[matches.length - 1] || [];
2822 var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
2823 var minutes = +(parts[1] * 60) + toInt(parts[2]);
2824
2825 return minutes === 0 ?
2826 0 :
2827 parts[0] === '+' ? minutes : -minutes;
2828 }
2829
2830 // Return a moment from input, that is local/utc/zone equivalent to model.
2831 function cloneWithOffset(input, model) {
2832 var res, diff;
2833 if (model._isUTC) {
2834 res = model.clone();
2835 diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
2836 // Use low-level api, because this fn is low-level api.
2837 res._d.setTime(res._d.valueOf() + diff);
2838 hooks.updateOffset(res, false);
2839 return res;
2840 } else {
2841 return createLocal(input).local();
2842 }
2843 }
2844
2845 function getDateOffset(m) {
2846 // On Firefox.24 Date#getTimezoneOffset returns a floating point.
2847 // https://github.com/moment/moment/pull/1871
2848 return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
2849 }
2850
2851 // HOOKS
2852
2853 // This function will be called whenever a moment is mutated.
2854 // It is intended to keep the offset in sync with the timezone.
2855 hooks.updateOffset = function () { };
2856
2857 // MOMENTS
2858
2859 // keepLocalTime = true means only change the timezone, without
2860 // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
2861 // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
2862 // +0200, so we adjust the time as needed, to be valid.
2863 //
2864 // Keeping the time actually adds/subtracts (one hour)
2865 // from the actual represented time. That is why we call updateOffset
2866 // a second time. In case it wants us to change the offset again
2867 // _changeInProgress == true case, then we have to adjust, because
2868 // there is no such time in the given timezone.
2869 function getSetOffset(input, keepLocalTime, keepMinutes) {
2870 var offset = this._offset || 0,
2871 localAdjust;
2872 if (!this.isValid()) {
2873 return input != null ? this : NaN;
2874 }
2875 if (input != null) {
2876 if (typeof input === 'string') {
2877 input = offsetFromString(matchShortOffset, input);
2878 if (input === null) {
2879 return this;
2880 }
2881 } else if (Math.abs(input) < 16 && !keepMinutes) {
2882 input = input * 60;
2883 }
2884 if (!this._isUTC && keepLocalTime) {
2885 localAdjust = getDateOffset(this);
2886 }
2887 this._offset = input;
2888 this._isUTC = true;
2889 if (localAdjust != null) {
2890 this.add(localAdjust, 'm');
2891 }
2892 if (offset !== input) {
2893 if (!keepLocalTime || this._changeInProgress) {
2894 addSubtract(this, createDuration(input - offset, 'm'), 1, false);
2895 } else if (!this._changeInProgress) {
2896 this._changeInProgress = true;
2897 hooks.updateOffset(this, true);
2898 this._changeInProgress = null;
2899 }
2900 }
2901 return this;
2902 } else {
2903 return this._isUTC ? offset : getDateOffset(this);
2904 }
2905 }
2906
2907 function getSetZone(input, keepLocalTime) {
2908 if (input != null) {
2909 if (typeof input !== 'string') {
2910 input = -input;
2911 }
2912
2913 this.utcOffset(input, keepLocalTime);
2914
2915 return this;
2916 } else {
2917 return -this.utcOffset();
2918 }
2919 }
2920
2921 function setOffsetToUTC(keepLocalTime) {
2922 return this.utcOffset(0, keepLocalTime);
2923 }
2924
2925 function setOffsetToLocal(keepLocalTime) {
2926 if (this._isUTC) {
2927 this.utcOffset(0, keepLocalTime);
2928 this._isUTC = false;
2929
2930 if (keepLocalTime) {
2931 this.subtract(getDateOffset(this), 'm');
2932 }
2933 }
2934 return this;
2935 }
2936
2937 function setOffsetToParsedOffset() {
2938 if (this._tzm != null) {
2939 this.utcOffset(this._tzm, false, true);
2940 } else if (typeof this._i === 'string') {
2941 var tZone = offsetFromString(matchOffset, this._i);
2942 if (tZone != null) {
2943 this.utcOffset(tZone);
2944 }
2945 else {
2946 this.utcOffset(0, true);
2947 }
2948 }
2949 return this;
2950 }
2951
2952 function hasAlignedHourOffset(input) {
2953 if (!this.isValid()) {
2954 return false;
2955 }
2956 input = input ? createLocal(input).utcOffset() : 0;
2957
2958 return (this.utcOffset() - input) % 60 === 0;
2959 }
2960
2961 function isDaylightSavingTime() {
2962 return (
2963 this.utcOffset() > this.clone().month(0).utcOffset() ||
2964 this.utcOffset() > this.clone().month(5).utcOffset()
2965 );
2966 }
2967
2968 function isDaylightSavingTimeShifted() {
2969 if (!isUndefined(this._isDSTShifted)) {
2970 return this._isDSTShifted;
2971 }
2972
2973 var c = {};
2974
2975 copyConfig(c, this);
2976 c = prepareConfig(c);
2977
2978 if (c._a) {
2979 var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
2980 this._isDSTShifted = this.isValid() &&
2981 compareArrays(c._a, other.toArray()) > 0;
2982 } else {
2983 this._isDSTShifted = false;
2984 }
2985
2986 return this._isDSTShifted;
2987 }
2988
2989 function isLocal() {
2990 return this.isValid() ? !this._isUTC : false;
2991 }
2992
2993 function isUtcOffset() {
2994 return this.isValid() ? this._isUTC : false;
2995 }
2996
2997 function isUtc() {
2998 return this.isValid() ? this._isUTC && this._offset === 0 : false;
2999 }
3000
3001 // ASP.NET json date format regex
3002 var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/;
3003
3004 // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
3005 // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
3006 // and further modified to allow for strings containing both week and day
3007 var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
3008
3009 function createDuration(input, key) {
3010 var duration = input,
3011 // matching against regexp is expensive, do it on demand
3012 match = null,
3013 sign,
3014 ret,
3015 diffRes;
3016
3017 if (isDuration(input)) {
3018 duration = {
3019 ms: input._milliseconds,
3020 d: input._days,
3021 M: input._months
3022 };
3023 } else if (isNumber(input)) {
3024 duration = {};
3025 if (key) {
3026 duration[key] = input;
3027 } else {
3028 duration.milliseconds = input;
3029 }
3030 } else if (!!(match = aspNetRegex.exec(input))) {
3031 sign = (match[1] === '-') ? -1 : 1;
3032 duration = {
3033 y: 0,
3034 d: toInt(match[DATE]) * sign,
3035 h: toInt(match[HOUR]) * sign,
3036 m: toInt(match[MINUTE]) * sign,
3037 s: toInt(match[SECOND]) * sign,
3038 ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
3039 };
3040 } else if (!!(match = isoRegex.exec(input))) {
3041 sign = (match[1] === '-') ? -1 : (match[1] === '+') ? 1 : 1;
3042 duration = {
3043 y: parseIso(match[2], sign),
3044 M: parseIso(match[3], sign),
3045 w: parseIso(match[4], sign),
3046 d: parseIso(match[5], sign),
3047 h: parseIso(match[6], sign),
3048 m: parseIso(match[7], sign),
3049 s: parseIso(match[8], sign)
3050 };
3051 } else if (duration == null) {// checks for null or undefined
3052 duration = {};
3053 } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
3054 diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
3055
3056 duration = {};
3057 duration.ms = diffRes.milliseconds;
3058 duration.M = diffRes.months;
3059 }
3060
3061 ret = new Duration(duration);
3062
3063 if (isDuration(input) && hasOwnProp(input, '_locale')) {
3064 ret._locale = input._locale;
3065 }
3066
3067 return ret;
3068 }
3069
3070 createDuration.fn = Duration.prototype;
3071 createDuration.invalid = createInvalid$1;
3072
3073 function parseIso(inp, sign) {
3074 // We'd normally use ~~inp for this, but unfortunately it also
3075 // converts floats to ints.
3076 // inp may be undefined, so careful calling replace on it.
3077 var res = inp && parseFloat(inp.replace(',', '.'));
3078 // apply sign while we're at it
3079 return (isNaN(res) ? 0 : res) * sign;
3080 }
3081
3082 function positiveMomentsDifference(base, other) {
3083 var res = { milliseconds: 0, months: 0 };
3084
3085 res.months = other.month() - base.month() +
3086 (other.year() - base.year()) * 12;
3087 if (base.clone().add(res.months, 'M').isAfter(other)) {
3088 --res.months;
3089 }
3090
3091 res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
3092
3093 return res;
3094 }
3095
3096 function momentsDifference(base, other) {
3097 var res;
3098 if (!(base.isValid() && other.isValid())) {
3099 return { milliseconds: 0, months: 0 };
3100 }
3101
3102 other = cloneWithOffset(other, base);
3103 if (base.isBefore(other)) {
3104 res = positiveMomentsDifference(base, other);
3105 } else {
3106 res = positiveMomentsDifference(other, base);
3107 res.milliseconds = -res.milliseconds;
3108 res.months = -res.months;
3109 }
3110
3111 return res;
3112 }
3113
3114 // TODO: remove 'name' arg after deprecation is removed
3115 function createAdder(direction, name) {
3116 return function (val, period) {
3117 var dur, tmp;
3118 //invert the arguments, but complain about it
3119 if (period !== null && !isNaN(+period)) {
3120 deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +
3121 'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
3122 tmp = val; val = period; period = tmp;
3123 }
3124
3125 val = typeof val === 'string' ? +val : val;
3126 dur = createDuration(val, period);
3127 addSubtract(this, dur, direction);
3128 return this;
3129 };
3130 }
3131
3132 function addSubtract(mom, duration, isAdding, updateOffset) {
3133 var milliseconds = duration._milliseconds,
3134 days = absRound(duration._days),
3135 months = absRound(duration._months);
3136
3137 if (!mom.isValid()) {
3138 // No op
3139 return;
3140 }
3141
3142 updateOffset = updateOffset == null ? true : updateOffset;
3143
3144 if (months) {
3145 setMonth(mom, get(mom, 'Month') + months * isAdding);
3146 }
3147 if (days) {
3148 set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
3149 }
3150 if (milliseconds) {
3151 mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
3152 }
3153 if (updateOffset) {
3154 hooks.updateOffset(mom, days || months);
3155 }
3156 }
3157
3158 var add = createAdder(1, 'add');
3159 var subtract = createAdder(-1, 'subtract');
3160
3161 function getCalendarFormat(myMoment, now) {
3162 var diff = myMoment.diff(now, 'days', true);
3163 return diff < -6 ? 'sameElse' :
3164 diff < -1 ? 'lastWeek' :
3165 diff < 0 ? 'lastDay' :
3166 diff < 1 ? 'sameDay' :
3167 diff < 2 ? 'nextDay' :
3168 diff < 7 ? 'nextWeek' : 'sameElse';
3169 }
3170
3171 function calendar$1(time, formats) {
3172 // We want to compare the start of today, vs this.
3173 // Getting start-of-today depends on whether we're local/utc/offset or not.
3174 var now = time || createLocal(),
3175 sod = cloneWithOffset(now, this).startOf('day'),
3176 format = hooks.calendarFormat(this, sod) || 'sameElse';
3177
3178 var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
3179
3180 return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
3181 }
3182
3183 function clone() {
3184 return new Moment(this);
3185 }
3186
3187 function isAfter(input, units) {
3188 var localInput = isMoment(input) ? input : createLocal(input);
3189 if (!(this.isValid() && localInput.isValid())) {
3190 return false;
3191 }
3192 units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
3193 if (units === 'millisecond') {
3194 return this.valueOf() > localInput.valueOf();
3195 } else {
3196 return localInput.valueOf() < this.clone().startOf(units).valueOf();
3197 }
3198 }
3199
3200 function isBefore(input, units) {
3201 var localInput = isMoment(input) ? input : createLocal(input);
3202 if (!(this.isValid() && localInput.isValid())) {
3203 return false;
3204 }
3205 units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
3206 if (units === 'millisecond') {
3207 return this.valueOf() < localInput.valueOf();
3208 } else {
3209 return this.clone().endOf(units).valueOf() < localInput.valueOf();
3210 }
3211 }
3212
3213 function isBetween(from, to, units, inclusivity) {
3214 inclusivity = inclusivity || '()';
3215 return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
3216 (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
3217 }
3218
3219 function isSame(input, units) {
3220 var localInput = isMoment(input) ? input : createLocal(input),
3221 inputMs;
3222 if (!(this.isValid() && localInput.isValid())) {
3223 return false;
3224 }
3225 units = normalizeUnits(units || 'millisecond');
3226 if (units === 'millisecond') {
3227 return this.valueOf() === localInput.valueOf();
3228 } else {
3229 inputMs = localInput.valueOf();
3230 return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
3231 }
3232 }
3233
3234 function isSameOrAfter(input, units) {
3235 return this.isSame(input, units) || this.isAfter(input, units);
3236 }
3237
3238 function isSameOrBefore(input, units) {
3239 return this.isSame(input, units) || this.isBefore(input, units);
3240 }
3241
3242 function diff(input, units, asFloat) {
3243 var that,
3244 zoneDelta,
3245 delta, output;
3246
3247 if (!this.isValid()) {
3248 return NaN;
3249 }
3250
3251 that = cloneWithOffset(input, this);
3252
3253 if (!that.isValid()) {
3254 return NaN;
3255 }
3256
3257 zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
3258
3259 units = normalizeUnits(units);
3260
3261 switch (units) {
3262 case 'year': output = monthDiff(this, that) / 12; break;
3263 case 'month': output = monthDiff(this, that); break;
3264 case 'quarter': output = monthDiff(this, that) / 3; break;
3265 case 'second': output = (this - that) / 1e3; break; // 1000
3266 case 'minute': output = (this - that) / 6e4; break; // 1000 * 60
3267 case 'hour': output = (this - that) / 36e5; break; // 1000 * 60 * 60
3268 case 'day': output = (this - that - zoneDelta) / 864e5; break; // 1000 * 60 * 60 * 24, negate dst
3269 case 'week': output = (this - that - zoneDelta) / 6048e5; break; // 1000 * 60 * 60 * 24 * 7, negate dst
3270 default: output = this - that;
3271 }
3272
3273 return asFloat ? output : absFloor(output);
3274 }
3275
3276 function monthDiff(a, b) {
3277 // difference in months
3278 var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
3279 // b is in (anchor - 1 month, anchor + 1 month)
3280 anchor = a.clone().add(wholeMonthDiff, 'months'),
3281 anchor2, adjust;
3282
3283 if (b - anchor < 0) {
3284 anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
3285 // linear across the month
3286 adjust = (b - anchor) / (anchor - anchor2);
3287 } else {
3288 anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
3289 // linear across the month
3290 adjust = (b - anchor) / (anchor2 - anchor);
3291 }
3292
3293 //check for negative zero, return zero if negative zero
3294 return -(wholeMonthDiff + adjust) || 0;
3295 }
3296
3297 hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
3298 hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
3299
3300 function toString() {
3301 return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
3302 }
3303
3304 function toISOString(keepOffset) {
3305 if (!this.isValid()) {
3306 return null;
3307 }
3308 var utc = keepOffset !== true;
3309 var m = utc ? this.clone().utc() : this;
3310 if (m.year() < 0 || m.year() > 9999) {
3311 return formatMoment(m, utc ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ');
3312 }
3313 if (isFunction(Date.prototype.toISOString)) {
3314 // native implementation is ~50x faster, use it when we can
3315 if (utc) {
3316 return this.toDate().toISOString();
3317 } else {
3318 return new Date(this._d.valueOf()).toISOString().replace('Z', formatMoment(m, 'Z'));
3319 }
3320 }
3321 return formatMoment(m, utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ');
3322 }
3323
3324 /**
3325 * Return a human readable representation of a moment that can
3326 * also be evaluated to get a new moment which is the same
3327 *
3328 * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
3329 */
3330 function inspect() {
3331 if (!this.isValid()) {
3332 return 'moment.invalid(/* ' + this._i + ' */)';
3333 }
3334 var func = 'moment';
3335 var zone = '';
3336 if (!this.isLocal()) {
3337 func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
3338 zone = 'Z';
3339 }
3340 var prefix = '[' + func + '("]';
3341 var year = (0 <= this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY';
3342 var datetime = '-MM-DD[T]HH:mm:ss.SSS';
3343 var suffix = zone + '[")]';
3344
3345 return this.format(prefix + year + datetime + suffix);
3346 }

1942 more lines aren’t shown here.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t