d4eb563b |
1 | //! moment.js |
2 | //! version : 2.8.4 |
3 | //! authors : Tim Wood, Iskren Chernev, Moment.js contributors |
4 | //! license : MIT |
5 | //! momentjs.com |
6 | |
7 | (function (undefined) { |
8 | /************************************ |
9 | Constants |
10 | ************************************/ |
11 | |
12 | var moment, |
13 | VERSION = '2.8.4', |
14 | // the global-scope this is NOT the global object in Node.js |
15 | globalScope = typeof global !== 'undefined' ? 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.zone(), |
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.zone(), |
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 | |
288 | lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin']; |
289 | |
290 | // Pick the first defined of two or three arguments. dfl comes from |
291 | // default. |
292 | function dfl(a, b, c) { |
293 | switch (arguments.length) { |
294 | case 2: return a != null ? a : b; |
295 | case 3: return a != null ? a : b != null ? b : c; |
296 | default: throw new Error('Implement me'); |
297 | } |
298 | } |
299 | |
300 | function hasOwnProp(a, b) { |
301 | return hasOwnProperty.call(a, b); |
302 | } |
303 | |
304 | function defaultParsingFlags() { |
305 | // We need to deep clone this object, and es5 standard is not very |
306 | // helpful. |
307 | return { |
308 | empty : false, |
309 | unusedTokens : [], |
310 | unusedInput : [], |
311 | overflow : -2, |
312 | charsLeftOver : 0, |
313 | nullInput : false, |
314 | invalidMonth : null, |
315 | invalidFormat : false, |
316 | userInvalidated : false, |
317 | iso: false |
318 | }; |
319 | } |
320 | |
321 | function printMsg(msg) { |
322 | if (moment.suppressDeprecationWarnings === false && |
323 | typeof console !== 'undefined' && console.warn) { |
324 | console.warn('Deprecation warning: ' + msg); |
325 | } |
326 | } |
327 | |
328 | function deprecate(msg, fn) { |
329 | var firstTime = true; |
330 | return extend(function () { |
331 | if (firstTime) { |
332 | printMsg(msg); |
333 | firstTime = false; |
334 | } |
335 | return fn.apply(this, arguments); |
336 | }, fn); |
337 | } |
338 | |
339 | function deprecateSimple(name, msg) { |
340 | if (!deprecations[name]) { |
341 | printMsg(msg); |
342 | deprecations[name] = true; |
343 | } |
344 | } |
345 | |
346 | function padToken(func, count) { |
347 | return function (a) { |
348 | return leftZeroFill(func.call(this, a), count); |
349 | }; |
350 | } |
351 | function ordinalizeToken(func, period) { |
352 | return function (a) { |
353 | return this.localeData().ordinal(func.call(this, a), period); |
354 | }; |
355 | } |
356 | |
357 | while (ordinalizeTokens.length) { |
358 | i = ordinalizeTokens.pop(); |
359 | formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); |
360 | } |
361 | while (paddedTokens.length) { |
362 | i = paddedTokens.pop(); |
363 | formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); |
364 | } |
365 | formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); |
366 | |
367 | |
368 | /************************************ |
369 | Constructors |
370 | ************************************/ |
371 | |
372 | function Locale() { |
373 | } |
374 | |
375 | // Moment prototype object |
376 | function Moment(config, skipOverflow) { |
377 | if (skipOverflow !== false) { |
378 | checkOverflow(config); |
379 | } |
380 | copyConfig(this, config); |
381 | this._d = new Date(+config._d); |
382 | } |
383 | |
384 | // Duration Constructor |
385 | function Duration(duration) { |
386 | var normalizedInput = normalizeObjectUnits(duration), |
387 | years = normalizedInput.year || 0, |
388 | quarters = normalizedInput.quarter || 0, |
389 | months = normalizedInput.month || 0, |
390 | weeks = normalizedInput.week || 0, |
391 | days = normalizedInput.day || 0, |
392 | hours = normalizedInput.hour || 0, |
393 | minutes = normalizedInput.minute || 0, |
394 | seconds = normalizedInput.second || 0, |
395 | milliseconds = normalizedInput.millisecond || 0; |
396 | |
397 | // representation for dateAddRemove |
398 | this._milliseconds = +milliseconds + |
399 | seconds * 1e3 + // 1000 |
400 | minutes * 6e4 + // 1000 * 60 |
401 | hours * 36e5; // 1000 * 60 * 60 |
402 | // Because of dateAddRemove treats 24 hours as different from a |
403 | // day when working around DST, we need to store them separately |
404 | this._days = +days + |
405 | weeks * 7; |
406 | // It is impossible translate months into days without knowing |
407 | // which months you are are talking about, so we have to store |
408 | // it separately. |
409 | this._months = +months + |
410 | quarters * 3 + |
411 | years * 12; |
412 | |
413 | this._data = {}; |
414 | |
415 | this._locale = moment.localeData(); |
416 | |
417 | this._bubble(); |
418 | } |
419 | |
420 | /************************************ |
421 | Helpers |
422 | ************************************/ |
423 | |
424 | |
425 | function extend(a, b) { |
426 | for (var i in b) { |
427 | if (hasOwnProp(b, i)) { |
428 | a[i] = b[i]; |
429 | } |
430 | } |
431 | |
432 | if (hasOwnProp(b, 'toString')) { |
433 | a.toString = b.toString; |
434 | } |
435 | |
436 | if (hasOwnProp(b, 'valueOf')) { |
437 | a.valueOf = b.valueOf; |
438 | } |
439 | |
440 | return a; |
441 | } |
442 | |
443 | function copyConfig(to, from) { |
444 | var i, prop, val; |
445 | |
446 | if (typeof from._isAMomentObject !== 'undefined') { |
447 | to._isAMomentObject = from._isAMomentObject; |
448 | } |
449 | if (typeof from._i !== 'undefined') { |
450 | to._i = from._i; |
451 | } |
452 | if (typeof from._f !== 'undefined') { |
453 | to._f = from._f; |
454 | } |
455 | if (typeof from._l !== 'undefined') { |
456 | to._l = from._l; |
457 | } |
458 | if (typeof from._strict !== 'undefined') { |
459 | to._strict = from._strict; |
460 | } |
461 | if (typeof from._tzm !== 'undefined') { |
462 | to._tzm = from._tzm; |
463 | } |
464 | if (typeof from._isUTC !== 'undefined') { |
465 | to._isUTC = from._isUTC; |
466 | } |
467 | if (typeof from._offset !== 'undefined') { |
468 | to._offset = from._offset; |
469 | } |
470 | if (typeof from._pf !== 'undefined') { |
471 | to._pf = from._pf; |
472 | } |
473 | if (typeof from._locale !== 'undefined') { |
474 | to._locale = from._locale; |
475 | } |
476 | |
477 | if (momentProperties.length > 0) { |
478 | for (i in momentProperties) { |
479 | prop = momentProperties[i]; |
480 | val = from[prop]; |
481 | if (typeof val !== 'undefined') { |
482 | to[prop] = val; |
483 | } |
484 | } |
485 | } |
486 | |
487 | return to; |
488 | } |
489 | |
490 | function absRound(number) { |
491 | if (number < 0) { |
492 | return Math.ceil(number); |
493 | } else { |
494 | return Math.floor(number); |
495 | } |
496 | } |
497 | |
498 | // left zero fill a number |
499 | // see http://jsperf.com/left-zero-filling for performance comparison |
500 | function leftZeroFill(number, targetLength, forceSign) { |
501 | var output = '' + Math.abs(number), |
502 | sign = number >= 0; |
503 | |
504 | while (output.length < targetLength) { |
505 | output = '0' + output; |
506 | } |
507 | return (sign ? (forceSign ? '+' : '') : '-') + output; |
508 | } |
509 | |
510 | function positiveMomentsDifference(base, other) { |
511 | var res = {milliseconds: 0, months: 0}; |
512 | |
513 | res.months = other.month() - base.month() + |
514 | (other.year() - base.year()) * 12; |
515 | if (base.clone().add(res.months, 'M').isAfter(other)) { |
516 | --res.months; |
517 | } |
518 | |
519 | res.milliseconds = +other - +(base.clone().add(res.months, 'M')); |
520 | |
521 | return res; |
522 | } |
523 | |
524 | function momentsDifference(base, other) { |
525 | var res; |
526 | other = makeAs(other, base); |
527 | if (base.isBefore(other)) { |
528 | res = positiveMomentsDifference(base, other); |
529 | } else { |
530 | res = positiveMomentsDifference(other, base); |
531 | res.milliseconds = -res.milliseconds; |
532 | res.months = -res.months; |
533 | } |
534 | |
535 | return res; |
536 | } |
537 | |
538 | // TODO: remove 'name' arg after deprecation is removed |
539 | function createAdder(direction, name) { |
540 | return function (val, period) { |
541 | var dur, tmp; |
542 | //invert the arguments, but complain about it |
543 | if (period !== null && !isNaN(+period)) { |
544 | deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).'); |
545 | tmp = val; val = period; period = tmp; |
546 | } |
547 | |
548 | val = typeof val === 'string' ? +val : val; |
549 | dur = moment.duration(val, period); |
550 | addOrSubtractDurationFromMoment(this, dur, direction); |
551 | return this; |
552 | }; |
553 | } |
554 | |
555 | function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) { |
556 | var milliseconds = duration._milliseconds, |
557 | days = duration._days, |
558 | months = duration._months; |
559 | updateOffset = updateOffset == null ? true : updateOffset; |
560 | |
561 | if (milliseconds) { |
562 | mom._d.setTime(+mom._d + milliseconds * isAdding); |
563 | } |
564 | if (days) { |
565 | rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding); |
566 | } |
567 | if (months) { |
568 | rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding); |
569 | } |
570 | if (updateOffset) { |
571 | moment.updateOffset(mom, days || months); |
572 | } |
573 | } |
574 | |
575 | // check if is an array |
576 | function isArray(input) { |
577 | return Object.prototype.toString.call(input) === '[object Array]'; |
578 | } |
579 | |
580 | function isDate(input) { |
581 | return Object.prototype.toString.call(input) === '[object Date]' || |
582 | input instanceof Date; |
583 | } |
584 | |
585 | // compare two arrays, return the number of differences |
586 | function compareArrays(array1, array2, dontConvert) { |
587 | var len = Math.min(array1.length, array2.length), |
588 | lengthDiff = Math.abs(array1.length - array2.length), |
589 | diffs = 0, |
590 | i; |
591 | for (i = 0; i < len; i++) { |
592 | if ((dontConvert && array1[i] !== array2[i]) || |
593 | (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { |
594 | diffs++; |
595 | } |
596 | } |
597 | return diffs + lengthDiff; |
598 | } |
599 | |
600 | function normalizeUnits(units) { |
601 | if (units) { |
602 | var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); |
603 | units = unitAliases[units] || camelFunctions[lowered] || lowered; |
604 | } |
605 | return units; |
606 | } |
607 | |
608 | function normalizeObjectUnits(inputObject) { |
609 | var normalizedInput = {}, |
610 | normalizedProp, |
611 | prop; |
612 | |
613 | for (prop in inputObject) { |
614 | if (hasOwnProp(inputObject, prop)) { |
615 | normalizedProp = normalizeUnits(prop); |
616 | if (normalizedProp) { |
617 | normalizedInput[normalizedProp] = inputObject[prop]; |
618 | } |
619 | } |
620 | } |
621 | |
622 | return normalizedInput; |
623 | } |
624 | |
625 | function makeList(field) { |
626 | var count, setter; |
627 | |
628 | if (field.indexOf('week') === 0) { |
629 | count = 7; |
630 | setter = 'day'; |
631 | } |
632 | else if (field.indexOf('month') === 0) { |
633 | count = 12; |
634 | setter = 'month'; |
635 | } |
636 | else { |
637 | return; |
638 | } |
639 | |
640 | moment[field] = function (format, index) { |
641 | var i, getter, |
642 | method = moment._locale[field], |
643 | results = []; |
644 | |
645 | if (typeof format === 'number') { |
646 | index = format; |
647 | format = undefined; |
648 | } |
649 | |
650 | getter = function (i) { |
651 | var m = moment().utc().set(setter, i); |
652 | return method.call(moment._locale, m, format || ''); |
653 | }; |
654 | |
655 | if (index != null) { |
656 | return getter(index); |
657 | } |
658 | else { |
659 | for (i = 0; i < count; i++) { |
660 | results.push(getter(i)); |
661 | } |
662 | return results; |
663 | } |
664 | }; |
665 | } |
666 | |
667 | function toInt(argumentForCoercion) { |
668 | var coercedNumber = +argumentForCoercion, |
669 | value = 0; |
670 | |
671 | if (coercedNumber !== 0 && isFinite(coercedNumber)) { |
672 | if (coercedNumber >= 0) { |
673 | value = Math.floor(coercedNumber); |
674 | } else { |
675 | value = Math.ceil(coercedNumber); |
676 | } |
677 | } |
678 | |
679 | return value; |
680 | } |
681 | |
682 | function daysInMonth(year, month) { |
683 | return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); |
684 | } |
685 | |
686 | function weeksInYear(year, dow, doy) { |
687 | return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week; |
688 | } |
689 | |
690 | function daysInYear(year) { |
691 | return isLeapYear(year) ? 366 : 365; |
692 | } |
693 | |
694 | function isLeapYear(year) { |
695 | return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; |
696 | } |
697 | |
698 | function checkOverflow(m) { |
699 | var overflow; |
700 | if (m._a && m._pf.overflow === -2) { |
701 | overflow = |
702 | m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : |
703 | m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : |
704 | m._a[HOUR] < 0 || m._a[HOUR] > 24 || |
705 | (m._a[HOUR] === 24 && (m._a[MINUTE] !== 0 || |
706 | m._a[SECOND] !== 0 || |
707 | m._a[MILLISECOND] !== 0)) ? HOUR : |
708 | m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : |
709 | m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : |
710 | m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : |
711 | -1; |
712 | |
713 | if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { |
714 | overflow = DATE; |
715 | } |
716 | |
717 | m._pf.overflow = overflow; |
718 | } |
719 | } |
720 | |
721 | function isValid(m) { |
722 | if (m._isValid == null) { |
723 | m._isValid = !isNaN(m._d.getTime()) && |
724 | m._pf.overflow < 0 && |
725 | !m._pf.empty && |
726 | !m._pf.invalidMonth && |
727 | !m._pf.nullInput && |
728 | !m._pf.invalidFormat && |
729 | !m._pf.userInvalidated; |
730 | |
731 | if (m._strict) { |
732 | m._isValid = m._isValid && |
733 | m._pf.charsLeftOver === 0 && |
734 | m._pf.unusedTokens.length === 0 && |
735 | m._pf.bigHour === undefined; |
736 | } |
737 | } |
738 | return m._isValid; |
739 | } |
740 | |
741 | function normalizeLocale(key) { |
742 | return key ? key.toLowerCase().replace('_', '-') : key; |
743 | } |
744 | |
745 | // pick the locale from the array |
746 | // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each |
747 | // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root |
748 | function chooseLocale(names) { |
749 | var i = 0, j, next, locale, split; |
750 | |
751 | while (i < names.length) { |
752 | split = normalizeLocale(names[i]).split('-'); |
753 | j = split.length; |
754 | next = normalizeLocale(names[i + 1]); |
755 | next = next ? next.split('-') : null; |
756 | while (j > 0) { |
757 | locale = loadLocale(split.slice(0, j).join('-')); |
758 | if (locale) { |
759 | return locale; |
760 | } |
761 | if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { |
762 | //the next array item is better than a shallower substring of this one |
763 | break; |
764 | } |
765 | j--; |
766 | } |
767 | i++; |
768 | } |
769 | return null; |
770 | } |
771 | |
772 | function loadLocale(name) { |
773 | var oldLocale = null; |
774 | if (!locales[name] && hasModule) { |
775 | try { |
776 | oldLocale = moment.locale(); |
777 | require('./locale/' + name); |
778 | // because defineLocale currently also sets the global locale, we want to undo that for lazy loaded locales |
779 | moment.locale(oldLocale); |
780 | } catch (e) { } |
781 | } |
782 | return locales[name]; |
783 | } |
784 | |
785 | // Return a moment from input, that is local/utc/zone equivalent to model. |
786 | function makeAs(input, model) { |
787 | var res, diff; |
788 | if (model._isUTC) { |
789 | res = model.clone(); |
790 | diff = (moment.isMoment(input) || isDate(input) ? |
791 | +input : +moment(input)) - (+res); |
792 | // Use low-level api, because this fn is low-level api. |
793 | res._d.setTime(+res._d + diff); |
794 | moment.updateOffset(res, false); |
795 | return res; |
796 | } else { |
797 | return moment(input).local(); |
798 | } |
799 | } |
800 | |
801 | /************************************ |
802 | Locale |
803 | ************************************/ |
804 | |
805 | |
806 | extend(Locale.prototype, { |
807 | |
808 | set : function (config) { |
809 | var prop, i; |
810 | for (i in config) { |
811 | prop = config[i]; |
812 | if (typeof prop === 'function') { |
813 | this[i] = prop; |
814 | } else { |
815 | this['_' + i] = prop; |
816 | } |
817 | } |
818 | // Lenient ordinal parsing accepts just a number in addition to |
819 | // number + (possibly) stuff coming from _ordinalParseLenient. |
820 | this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + /\d{1,2}/.source); |
821 | }, |
822 | |
823 | _months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), |
824 | months : function (m) { |
825 | return this._months[m.month()]; |
826 | }, |
827 | |
828 | _monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), |
829 | monthsShort : function (m) { |
830 | return this._monthsShort[m.month()]; |
831 | }, |
832 | |
833 | monthsParse : function (monthName, format, strict) { |
834 | var i, mom, regex; |
835 | |
836 | if (!this._monthsParse) { |
837 | this._monthsParse = []; |
838 | this._longMonthsParse = []; |
839 | this._shortMonthsParse = []; |
840 | } |
841 | |
842 | for (i = 0; i < 12; i++) { |
843 | // make the regex if we don't have it already |
844 | mom = moment.utc([2000, i]); |
845 | if (strict && !this._longMonthsParse[i]) { |
846 | this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); |
847 | this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); |
848 | } |
849 | if (!strict && !this._monthsParse[i]) { |
850 | regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); |
851 | this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); |
852 | } |
853 | // test the regex |
854 | if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { |
855 | return i; |
856 | } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { |
857 | return i; |
858 | } else if (!strict && this._monthsParse[i].test(monthName)) { |
859 | return i; |
860 | } |
861 | } |
862 | }, |
863 | |
864 | _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), |
865 | weekdays : function (m) { |
866 | return this._weekdays[m.day()]; |
867 | }, |
868 | |
869 | _weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), |
870 | weekdaysShort : function (m) { |
871 | return this._weekdaysShort[m.day()]; |
872 | }, |
873 | |
874 | _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), |
875 | weekdaysMin : function (m) { |
876 | return this._weekdaysMin[m.day()]; |
877 | }, |
878 | |
879 | weekdaysParse : function (weekdayName) { |
880 | var i, mom, regex; |
881 | |
882 | if (!this._weekdaysParse) { |
883 | this._weekdaysParse = []; |
884 | } |
885 | |
886 | for (i = 0; i < 7; i++) { |
887 | // make the regex if we don't have it already |
888 | if (!this._weekdaysParse[i]) { |
889 | mom = moment([2000, 1]).day(i); |
890 | regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); |
891 | this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); |
892 | } |
893 | // test the regex |
894 | if (this._weekdaysParse[i].test(weekdayName)) { |
895 | return i; |
896 | } |
897 | } |
898 | }, |
899 | |
900 | _longDateFormat : { |
901 | LTS : 'h:mm:ss A', |
902 | LT : 'h:mm A', |
903 | L : 'MM/DD/YYYY', |
904 | LL : 'MMMM D, YYYY', |
905 | LLL : 'MMMM D, YYYY LT', |
906 | LLLL : 'dddd, MMMM D, YYYY LT' |
907 | }, |
908 | longDateFormat : function (key) { |
909 | var output = this._longDateFormat[key]; |
910 | if (!output && this._longDateFormat[key.toUpperCase()]) { |
911 | output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { |
912 | return val.slice(1); |
913 | }); |
914 | this._longDateFormat[key] = output; |
915 | } |
916 | return output; |
917 | }, |
918 | |
919 | isPM : function (input) { |
920 | // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays |
921 | // Using charAt should be more compatible. |
922 | return ((input + '').toLowerCase().charAt(0) === 'p'); |
923 | }, |
924 | |
925 | _meridiemParse : /[ap]\.?m?\.?/i, |
926 | meridiem : function (hours, minutes, isLower) { |
927 | if (hours > 11) { |
928 | return isLower ? 'pm' : 'PM'; |
929 | } else { |
930 | return isLower ? 'am' : 'AM'; |
931 | } |
932 | }, |
933 | |
934 | _calendar : { |
935 | sameDay : '[Today at] LT', |
936 | nextDay : '[Tomorrow at] LT', |
937 | nextWeek : 'dddd [at] LT', |
938 | lastDay : '[Yesterday at] LT', |
939 | lastWeek : '[Last] dddd [at] LT', |
940 | sameElse : 'L' |
941 | }, |
942 | calendar : function (key, mom, now) { |
943 | var output = this._calendar[key]; |
944 | return typeof output === 'function' ? output.apply(mom, [now]) : output; |
945 | }, |
946 | |
947 | _relativeTime : { |
948 | future : 'in %s', |
949 | past : '%s ago', |
950 | s : 'a few seconds', |
951 | m : 'a minute', |
952 | mm : '%d minutes', |
953 | h : 'an hour', |
954 | hh : '%d hours', |
955 | d : 'a day', |
956 | dd : '%d days', |
957 | M : 'a month', |
958 | MM : '%d months', |
959 | y : 'a year', |
960 | yy : '%d years' |
961 | }, |
962 | |
963 | relativeTime : function (number, withoutSuffix, string, isFuture) { |
964 | var output = this._relativeTime[string]; |
965 | return (typeof output === 'function') ? |
966 | output(number, withoutSuffix, string, isFuture) : |
967 | output.replace(/%d/i, number); |
968 | }, |
969 | |
970 | pastFuture : function (diff, output) { |
971 | var format = this._relativeTime[diff > 0 ? 'future' : 'past']; |
972 | return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); |
973 | }, |
974 | |
975 | ordinal : function (number) { |
976 | return this._ordinal.replace('%d', number); |
977 | }, |
978 | _ordinal : '%d', |
979 | _ordinalParse : /\d{1,2}/, |
980 | |
981 | preparse : function (string) { |
982 | return string; |
983 | }, |
984 | |
985 | postformat : function (string) { |
986 | return string; |
987 | }, |
988 | |
989 | week : function (mom) { |
990 | return weekOfYear(mom, this._week.dow, this._week.doy).week; |
991 | }, |
992 | |
993 | _week : { |
994 | dow : 0, // Sunday is the first day of the week. |
995 | doy : 6 // The week that contains Jan 1st is the first week of the year. |
996 | }, |
997 | |
998 | _invalidDate: 'Invalid date', |
999 | invalidDate: function () { |
1000 | return this._invalidDate; |
1001 | } |
1002 | }); |
1003 | |
1004 | /************************************ |
1005 | Formatting |
1006 | ************************************/ |
1007 | |
1008 | |
1009 | function removeFormattingTokens(input) { |
1010 | if (input.match(/\[[\s\S]/)) { |
1011 | return input.replace(/^\[|\]$/g, ''); |
1012 | } |
1013 | return input.replace(/\\/g, ''); |
1014 | } |
1015 | |
1016 | function makeFormatFunction(format) { |
1017 | var array = format.match(formattingTokens), i, length; |
1018 | |
1019 | for (i = 0, length = array.length; i < length; i++) { |
1020 | if (formatTokenFunctions[array[i]]) { |
1021 | array[i] = formatTokenFunctions[array[i]]; |
1022 | } else { |
1023 | array[i] = removeFormattingTokens(array[i]); |
1024 | } |
1025 | } |
1026 | |
1027 | return function (mom) { |
1028 | var output = ''; |
1029 | for (i = 0; i < length; i++) { |
1030 | output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; |
1031 | } |
1032 | return output; |
1033 | }; |
1034 | } |
1035 | |
1036 | // format date using native date object |
1037 | function formatMoment(m, format) { |
1038 | if (!m.isValid()) { |
1039 | return m.localeData().invalidDate(); |
1040 | } |
1041 | |
1042 | format = expandFormat(format, m.localeData()); |
1043 | |
1044 | if (!formatFunctions[format]) { |
1045 | formatFunctions[format] = makeFormatFunction(format); |
1046 | } |
1047 | |
1048 | return formatFunctions[format](m); |
1049 | } |
1050 | |
1051 | function expandFormat(format, locale) { |
1052 | var i = 5; |
1053 | |
1054 | function replaceLongDateFormatTokens(input) { |
1055 | return locale.longDateFormat(input) || input; |
1056 | } |
1057 | |
1058 | localFormattingTokens.lastIndex = 0; |
1059 | while (i >= 0 && localFormattingTokens.test(format)) { |
1060 | format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); |
1061 | localFormattingTokens.lastIndex = 0; |
1062 | i -= 1; |
1063 | } |
1064 | |
1065 | return format; |
1066 | } |
1067 | |
1068 | |
1069 | /************************************ |
1070 | Parsing |
1071 | ************************************/ |
1072 | |
1073 | |
1074 | // get the regex to find the next token |
1075 | function getParseRegexForToken(token, config) { |
1076 | var a, strict = config._strict; |
1077 | switch (token) { |
1078 | case 'Q': |
1079 | return parseTokenOneDigit; |
1080 | case 'DDDD': |
1081 | return parseTokenThreeDigits; |
1082 | case 'YYYY': |
1083 | case 'GGGG': |
1084 | case 'gggg': |
1085 | return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; |
1086 | case 'Y': |
1087 | case 'G': |
1088 | case 'g': |
1089 | return parseTokenSignedNumber; |
1090 | case 'YYYYYY': |
1091 | case 'YYYYY': |
1092 | case 'GGGGG': |
1093 | case 'ggggg': |
1094 | return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; |
1095 | case 'S': |
1096 | if (strict) { |
1097 | return parseTokenOneDigit; |
1098 | } |
1099 | /* falls through */ |
1100 | case 'SS': |
1101 | if (strict) { |
1102 | return parseTokenTwoDigits; |
1103 | } |
1104 | /* falls through */ |
1105 | case 'SSS': |
1106 | if (strict) { |
1107 | return parseTokenThreeDigits; |
1108 | } |
1109 | /* falls through */ |
1110 | case 'DDD': |
1111 | return parseTokenOneToThreeDigits; |
1112 | case 'MMM': |
1113 | case 'MMMM': |
1114 | case 'dd': |
1115 | case 'ddd': |
1116 | case 'dddd': |
1117 | return parseTokenWord; |
1118 | case 'a': |
1119 | case 'A': |
1120 | return config._locale._meridiemParse; |
1121 | case 'x': |
1122 | return parseTokenOffsetMs; |
1123 | case 'X': |
1124 | return parseTokenTimestampMs; |
1125 | case 'Z': |
1126 | case 'ZZ': |
1127 | return parseTokenTimezone; |
1128 | case 'T': |
1129 | return parseTokenT; |
1130 | case 'SSSS': |
1131 | return parseTokenDigits; |
1132 | case 'MM': |
1133 | case 'DD': |
1134 | case 'YY': |
1135 | case 'GG': |
1136 | case 'gg': |
1137 | case 'HH': |
1138 | case 'hh': |
1139 | case 'mm': |
1140 | case 'ss': |
1141 | case 'ww': |
1142 | case 'WW': |
1143 | return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; |
1144 | case 'M': |
1145 | case 'D': |
1146 | case 'd': |
1147 | case 'H': |
1148 | case 'h': |
1149 | case 'm': |
1150 | case 's': |
1151 | case 'w': |
1152 | case 'W': |
1153 | case 'e': |
1154 | case 'E': |
1155 | return parseTokenOneOrTwoDigits; |
1156 | case 'Do': |
1157 | return strict ? config._locale._ordinalParse : config._locale._ordinalParseLenient; |
1158 | default : |
1159 | a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i')); |
1160 | return a; |
1161 | } |
1162 | } |
1163 | |
1164 | function timezoneMinutesFromString(string) { |
1165 | string = string || ''; |
1166 | var possibleTzMatches = (string.match(parseTokenTimezone) || []), |
1167 | tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], |
1168 | parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], |
1169 | minutes = +(parts[1] * 60) + toInt(parts[2]); |
1170 | |
1171 | return parts[0] === '+' ? -minutes : minutes; |
1172 | } |
1173 | |
1174 | // function to convert string input to date |
1175 | function addTimeToArrayFromToken(token, input, config) { |
1176 | var a, datePartArray = config._a; |
1177 | |
1178 | switch (token) { |
1179 | // QUARTER |
1180 | case 'Q': |
1181 | if (input != null) { |
1182 | datePartArray[MONTH] = (toInt(input) - 1) * 3; |
1183 | } |
1184 | break; |
1185 | // MONTH |
1186 | case 'M' : // fall through to MM |
1187 | case 'MM' : |
1188 | if (input != null) { |
1189 | datePartArray[MONTH] = toInt(input) - 1; |
1190 | } |
1191 | break; |
1192 | case 'MMM' : // fall through to MMMM |
1193 | case 'MMMM' : |
1194 | a = config._locale.monthsParse(input, token, config._strict); |
1195 | // if we didn't find a month name, mark the date as invalid. |
1196 | if (a != null) { |
1197 | datePartArray[MONTH] = a; |
1198 | } else { |
1199 | config._pf.invalidMonth = input; |
1200 | } |
1201 | break; |
1202 | // DAY OF MONTH |
1203 | case 'D' : // fall through to DD |
1204 | case 'DD' : |
1205 | if (input != null) { |
1206 | datePartArray[DATE] = toInt(input); |
1207 | } |
1208 | break; |
1209 | case 'Do' : |
1210 | if (input != null) { |
1211 | datePartArray[DATE] = toInt(parseInt( |
1212 | input.match(/\d{1,2}/)[0], 10)); |
1213 | } |
1214 | break; |
1215 | // DAY OF YEAR |
1216 | case 'DDD' : // fall through to DDDD |
1217 | case 'DDDD' : |
1218 | if (input != null) { |
1219 | config._dayOfYear = toInt(input); |
1220 | } |
1221 | |
1222 | break; |
1223 | // YEAR |
1224 | case 'YY' : |
1225 | datePartArray[YEAR] = moment.parseTwoDigitYear(input); |
1226 | break; |
1227 | case 'YYYY' : |
1228 | case 'YYYYY' : |
1229 | case 'YYYYYY' : |
1230 | datePartArray[YEAR] = toInt(input); |
1231 | break; |
1232 | // AM / PM |
1233 | case 'a' : // fall through to A |
1234 | case 'A' : |
1235 | config._isPm = config._locale.isPM(input); |
1236 | break; |
1237 | // HOUR |
1238 | case 'h' : // fall through to hh |
1239 | case 'hh' : |
1240 | config._pf.bigHour = true; |
1241 | /* falls through */ |
1242 | case 'H' : // fall through to HH |
1243 | case 'HH' : |
1244 | datePartArray[HOUR] = toInt(input); |
1245 | break; |
1246 | // MINUTE |
1247 | case 'm' : // fall through to mm |
1248 | case 'mm' : |
1249 | datePartArray[MINUTE] = toInt(input); |
1250 | break; |
1251 | // SECOND |
1252 | case 's' : // fall through to ss |
1253 | case 'ss' : |
1254 | datePartArray[SECOND] = toInt(input); |
1255 | break; |
1256 | // MILLISECOND |
1257 | case 'S' : |
1258 | case 'SS' : |
1259 | case 'SSS' : |
1260 | case 'SSSS' : |
1261 | datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); |
1262 | break; |
1263 | // UNIX OFFSET (MILLISECONDS) |
1264 | case 'x': |
1265 | config._d = new Date(toInt(input)); |
1266 | break; |
1267 | // UNIX TIMESTAMP WITH MS |
1268 | case 'X': |
1269 | config._d = new Date(parseFloat(input) * 1000); |
1270 | break; |
1271 | // TIMEZONE |
1272 | case 'Z' : // fall through to ZZ |
1273 | case 'ZZ' : |
1274 | config._useUTC = true; |
1275 | config._tzm = timezoneMinutesFromString(input); |
1276 | break; |
1277 | // WEEKDAY - human |
1278 | case 'dd': |
1279 | case 'ddd': |
1280 | case 'dddd': |
1281 | a = config._locale.weekdaysParse(input); |
1282 | // if we didn't get a weekday name, mark the date as invalid |
1283 | if (a != null) { |
1284 | config._w = config._w || {}; |
1285 | config._w['d'] = a; |
1286 | } else { |
1287 | config._pf.invalidWeekday = input; |
1288 | } |
1289 | break; |
1290 | // WEEK, WEEK DAY - numeric |
1291 | case 'w': |
1292 | case 'ww': |
1293 | case 'W': |
1294 | case 'WW': |
1295 | case 'd': |
1296 | case 'e': |
1297 | case 'E': |
1298 | token = token.substr(0, 1); |
1299 | /* falls through */ |
1300 | case 'gggg': |
1301 | case 'GGGG': |
1302 | case 'GGGGG': |
1303 | token = token.substr(0, 2); |
1304 | if (input) { |
1305 | config._w = config._w || {}; |
1306 | config._w[token] = toInt(input); |
1307 | } |
1308 | break; |
1309 | case 'gg': |
1310 | case 'GG': |
1311 | config._w = config._w || {}; |
1312 | config._w[token] = moment.parseTwoDigitYear(input); |
1313 | } |
1314 | } |
1315 | |
1316 | function dayOfYearFromWeekInfo(config) { |
1317 | var w, weekYear, week, weekday, dow, doy, temp; |
1318 | |
1319 | w = config._w; |
1320 | if (w.GG != null || w.W != null || w.E != null) { |
1321 | dow = 1; |
1322 | doy = 4; |
1323 | |
1324 | // TODO: We need to take the current isoWeekYear, but that depends on |
1325 | // how we interpret now (local, utc, fixed offset). So create |
1326 | // a now version of current config (take local/utc/offset flags, and |
1327 | // create now). |
1328 | weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year); |
1329 | week = dfl(w.W, 1); |
1330 | weekday = dfl(w.E, 1); |
1331 | } else { |
1332 | dow = config._locale._week.dow; |
1333 | doy = config._locale._week.doy; |
1334 | |
1335 | weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year); |
1336 | week = dfl(w.w, 1); |
1337 | |
1338 | if (w.d != null) { |
1339 | // weekday -- low day numbers are considered next week |
1340 | weekday = w.d; |
1341 | if (weekday < dow) { |
1342 | ++week; |
1343 | } |
1344 | } else if (w.e != null) { |
1345 | // local weekday -- counting starts from begining of week |
1346 | weekday = w.e + dow; |
1347 | } else { |
1348 | // default to begining of week |
1349 | weekday = dow; |
1350 | } |
1351 | } |
1352 | temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); |
1353 | |
1354 | config._a[YEAR] = temp.year; |
1355 | config._dayOfYear = temp.dayOfYear; |
1356 | } |
1357 | |
1358 | // convert an array to a date. |
1359 | // the array should mirror the parameters below |
1360 | // note: all values past the year are optional and will default to the lowest possible value. |
1361 | // [year, month, day , hour, minute, second, millisecond] |
1362 | function dateFromConfig(config) { |
1363 | var i, date, input = [], currentDate, yearToUse; |
1364 | |
1365 | if (config._d) { |
1366 | return; |
1367 | } |
1368 | |
1369 | currentDate = currentDateArray(config); |
1370 | |
1371 | //compute day of the year from weeks and weekdays |
1372 | if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { |
1373 | dayOfYearFromWeekInfo(config); |
1374 | } |
1375 | |
1376 | //if the day of the year is set, figure out what it is |
1377 | if (config._dayOfYear) { |
1378 | yearToUse = dfl(config._a[YEAR], currentDate[YEAR]); |
1379 | |
1380 | if (config._dayOfYear > daysInYear(yearToUse)) { |
1381 | config._pf._overflowDayOfYear = true; |
1382 | } |
1383 | |
1384 | date = makeUTCDate(yearToUse, 0, config._dayOfYear); |
1385 | config._a[MONTH] = date.getUTCMonth(); |
1386 | config._a[DATE] = date.getUTCDate(); |
1387 | } |
1388 | |
1389 | // Default to current date. |
1390 | // * if no year, month, day of month are given, default to today |
1391 | // * if day of month is given, default month and year |
1392 | // * if month is given, default only year |
1393 | // * if year is given, don't default anything |
1394 | for (i = 0; i < 3 && config._a[i] == null; ++i) { |
1395 | config._a[i] = input[i] = currentDate[i]; |
1396 | } |
1397 | |
1398 | // Zero out whatever was not defaulted, including time |
1399 | for (; i < 7; i++) { |
1400 | config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; |
1401 | } |
1402 | |
1403 | // Check for 24:00:00.000 |
1404 | if (config._a[HOUR] === 24 && |
1405 | config._a[MINUTE] === 0 && |
1406 | config._a[SECOND] === 0 && |
1407 | config._a[MILLISECOND] === 0) { |
1408 | config._nextDay = true; |
1409 | config._a[HOUR] = 0; |
1410 | } |
1411 | |
1412 | config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); |
1413 | // Apply timezone offset from input. The actual zone can be changed |
1414 | // with parseZone. |
1415 | if (config._tzm != null) { |
1416 | config._d.setUTCMinutes(config._d.getUTCMinutes() + config._tzm); |
1417 | } |
1418 | |
1419 | if (config._nextDay) { |
1420 | config._a[HOUR] = 24; |
1421 | } |
1422 | } |
1423 | |
1424 | function dateFromObject(config) { |
1425 | var normalizedInput; |
1426 | |
1427 | if (config._d) { |
1428 | return; |
1429 | } |
1430 | |
1431 | normalizedInput = normalizeObjectUnits(config._i); |
1432 | config._a = [ |
1433 | normalizedInput.year, |
1434 | normalizedInput.month, |
1435 | normalizedInput.day || normalizedInput.date, |
1436 | normalizedInput.hour, |
1437 | normalizedInput.minute, |
1438 | normalizedInput.second, |
1439 | normalizedInput.millisecond |
1440 | ]; |
1441 | |
1442 | dateFromConfig(config); |
1443 | } |
1444 | |
1445 | function currentDateArray(config) { |
1446 | var now = new Date(); |
1447 | if (config._useUTC) { |
1448 | return [ |
1449 | now.getUTCFullYear(), |
1450 | now.getUTCMonth(), |
1451 | now.getUTCDate() |
1452 | ]; |
1453 | } else { |
1454 | return [now.getFullYear(), now.getMonth(), now.getDate()]; |
1455 | } |
1456 | } |
1457 | |
1458 | // date from string and format string |
1459 | function makeDateFromStringAndFormat(config) { |
1460 | if (config._f === moment.ISO_8601) { |
1461 | parseISO(config); |
1462 | return; |
1463 | } |
1464 | |
1465 | config._a = []; |
1466 | config._pf.empty = true; |
1467 | |
1468 | // This array is used to make a Date, either with `new Date` or `Date.UTC` |
1469 | var string = '' + config._i, |
1470 | i, parsedInput, tokens, token, skipped, |
1471 | stringLength = string.length, |
1472 | totalParsedInputLength = 0; |
1473 | |
1474 | tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; |
1475 | |
1476 | for (i = 0; i < tokens.length; i++) { |
1477 | token = tokens[i]; |
1478 | parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; |
1479 | if (parsedInput) { |
1480 | skipped = string.substr(0, string.indexOf(parsedInput)); |
1481 | if (skipped.length > 0) { |
1482 | config._pf.unusedInput.push(skipped); |
1483 | } |
1484 | string = string.slice(string.indexOf(parsedInput) + parsedInput.length); |
1485 | totalParsedInputLength += parsedInput.length; |
1486 | } |
1487 | // don't parse if it's not a known token |
1488 | if (formatTokenFunctions[token]) { |
1489 | if (parsedInput) { |
1490 | config._pf.empty = false; |
1491 | } |
1492 | else { |
1493 | config._pf.unusedTokens.push(token); |
1494 | } |
1495 | addTimeToArrayFromToken(token, parsedInput, config); |
1496 | } |
1497 | else if (config._strict && !parsedInput) { |
1498 | config._pf.unusedTokens.push(token); |
1499 | } |
1500 | } |
1501 | |
1502 | // add remaining unparsed input length to the string |
1503 | config._pf.charsLeftOver = stringLength - totalParsedInputLength; |
1504 | if (string.length > 0) { |
1505 | config._pf.unusedInput.push(string); |
1506 | } |
1507 | |
1508 | // clear _12h flag if hour is <= 12 |
1509 | if (config._pf.bigHour === true && config._a[HOUR] <= 12) { |
1510 | config._pf.bigHour = undefined; |
1511 | } |
1512 | // handle am pm |
1513 | if (config._isPm && config._a[HOUR] < 12) { |
1514 | config._a[HOUR] += 12; |
1515 | } |
1516 | // if is 12 am, change hours to 0 |
1517 | if (config._isPm === false && config._a[HOUR] === 12) { |
1518 | config._a[HOUR] = 0; |
1519 | } |
1520 | dateFromConfig(config); |
1521 | checkOverflow(config); |
1522 | } |
1523 | |
1524 | function unescapeFormat(s) { |
1525 | return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { |
1526 | return p1 || p2 || p3 || p4; |
1527 | }); |
1528 | } |
1529 | |
1530 | // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript |
1531 | function regexpEscape(s) { |
1532 | return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); |
1533 | } |
1534 | |
1535 | // date from string and array of format strings |
1536 | function makeDateFromStringAndArray(config) { |
1537 | var tempConfig, |
1538 | bestMoment, |
1539 | |
1540 | scoreToBeat, |
1541 | i, |
1542 | currentScore; |
1543 | |
1544 | if (config._f.length === 0) { |
1545 | config._pf.invalidFormat = true; |
1546 | config._d = new Date(NaN); |
1547 | return; |
1548 | } |
1549 | |
1550 | for (i = 0; i < config._f.length; i++) { |
1551 | currentScore = 0; |
1552 | tempConfig = copyConfig({}, config); |
1553 | if (config._useUTC != null) { |
1554 | tempConfig._useUTC = config._useUTC; |
1555 | } |
1556 | tempConfig._pf = defaultParsingFlags(); |
1557 | tempConfig._f = config._f[i]; |
1558 | makeDateFromStringAndFormat(tempConfig); |
1559 | |
1560 | if (!isValid(tempConfig)) { |
1561 | continue; |
1562 | } |
1563 | |
1564 | // if there is any input that was not parsed add a penalty for that format |
1565 | currentScore += tempConfig._pf.charsLeftOver; |
1566 | |
1567 | //or tokens |
1568 | currentScore += tempConfig._pf.unusedTokens.length * 10; |
1569 | |
1570 | tempConfig._pf.score = currentScore; |
1571 | |
1572 | if (scoreToBeat == null || currentScore < scoreToBeat) { |
1573 | scoreToBeat = currentScore; |
1574 | bestMoment = tempConfig; |
1575 | } |
1576 | } |
1577 | |
1578 | extend(config, bestMoment || tempConfig); |
1579 | } |
1580 | |
1581 | // date from iso format |
1582 | function parseISO(config) { |
1583 | var i, l, |
1584 | string = config._i, |
1585 | match = isoRegex.exec(string); |
1586 | |
1587 | if (match) { |
1588 | config._pf.iso = true; |
1589 | for (i = 0, l = isoDates.length; i < l; i++) { |
1590 | if (isoDates[i][1].exec(string)) { |
1591 | // match[5] should be 'T' or undefined |
1592 | config._f = isoDates[i][0] + (match[6] || ' '); |
1593 | break; |
1594 | } |
1595 | } |
1596 | for (i = 0, l = isoTimes.length; i < l; i++) { |
1597 | if (isoTimes[i][1].exec(string)) { |
1598 | config._f += isoTimes[i][0]; |
1599 | break; |
1600 | } |
1601 | } |
1602 | if (string.match(parseTokenTimezone)) { |
1603 | config._f += 'Z'; |
1604 | } |
1605 | makeDateFromStringAndFormat(config); |
1606 | } else { |
1607 | config._isValid = false; |
1608 | } |
1609 | } |
1610 | |
1611 | // date from iso format or fallback |
1612 | function makeDateFromString(config) { |
1613 | parseISO(config); |
1614 | if (config._isValid === false) { |
1615 | delete config._isValid; |
1616 | moment.createFromInputFallback(config); |
1617 | } |
1618 | } |
1619 | |
1620 | function map(arr, fn) { |
1621 | var res = [], i; |
1622 | for (i = 0; i < arr.length; ++i) { |
1623 | res.push(fn(arr[i], i)); |
1624 | } |
1625 | return res; |
1626 | } |
1627 | |
1628 | function makeDateFromInput(config) { |
1629 | var input = config._i, matched; |
1630 | if (input === undefined) { |
1631 | config._d = new Date(); |
1632 | } else if (isDate(input)) { |
1633 | config._d = new Date(+input); |
1634 | } else if ((matched = aspNetJsonRegex.exec(input)) !== null) { |
1635 | config._d = new Date(+matched[1]); |
1636 | } else if (typeof input === 'string') { |
1637 | makeDateFromString(config); |
1638 | } else if (isArray(input)) { |
1639 | config._a = map(input.slice(0), function (obj) { |
1640 | return parseInt(obj, 10); |
1641 | }); |
1642 | dateFromConfig(config); |
1643 | } else if (typeof(input) === 'object') { |
1644 | dateFromObject(config); |
1645 | } else if (typeof(input) === 'number') { |
1646 | // from milliseconds |
1647 | config._d = new Date(input); |
1648 | } else { |
1649 | moment.createFromInputFallback(config); |
1650 | } |
1651 | } |
1652 | |
1653 | function makeDate(y, m, d, h, M, s, ms) { |
1654 | //can't just apply() to create a date: |
1655 | //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply |
1656 | var date = new Date(y, m, d, h, M, s, ms); |
1657 | |
1658 | //the date constructor doesn't accept years < 1970 |
1659 | if (y < 1970) { |
1660 | date.setFullYear(y); |
1661 | } |
1662 | return date; |
1663 | } |
1664 | |
1665 | function makeUTCDate(y) { |
1666 | var date = new Date(Date.UTC.apply(null, arguments)); |
1667 | if (y < 1970) { |
1668 | date.setUTCFullYear(y); |
1669 | } |
1670 | return date; |
1671 | } |
1672 | |
1673 | function parseWeekday(input, locale) { |
1674 | if (typeof input === 'string') { |
1675 | if (!isNaN(input)) { |
1676 | input = parseInt(input, 10); |
1677 | } |
1678 | else { |
1679 | input = locale.weekdaysParse(input); |
1680 | if (typeof input !== 'number') { |
1681 | return null; |
1682 | } |
1683 | } |
1684 | } |
1685 | return input; |
1686 | } |
1687 | |
1688 | /************************************ |
1689 | Relative Time |
1690 | ************************************/ |
1691 | |
1692 | |
1693 | // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize |
1694 | function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { |
1695 | return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); |
1696 | } |
1697 | |
1698 | function relativeTime(posNegDuration, withoutSuffix, locale) { |
1699 | var duration = moment.duration(posNegDuration).abs(), |
1700 | seconds = round(duration.as('s')), |
1701 | minutes = round(duration.as('m')), |
1702 | hours = round(duration.as('h')), |
1703 | days = round(duration.as('d')), |
1704 | months = round(duration.as('M')), |
1705 | years = round(duration.as('y')), |
1706 | |
1707 | args = seconds < relativeTimeThresholds.s && ['s', seconds] || |
1708 | minutes === 1 && ['m'] || |
1709 | minutes < relativeTimeThresholds.m && ['mm', minutes] || |
1710 | hours === 1 && ['h'] || |
1711 | hours < relativeTimeThresholds.h && ['hh', hours] || |
1712 | days === 1 && ['d'] || |
1713 | days < relativeTimeThresholds.d && ['dd', days] || |
1714 | months === 1 && ['M'] || |
1715 | months < relativeTimeThresholds.M && ['MM', months] || |
1716 | years === 1 && ['y'] || ['yy', years]; |
1717 | |
1718 | args[2] = withoutSuffix; |
1719 | args[3] = +posNegDuration > 0; |
1720 | args[4] = locale; |
1721 | return substituteTimeAgo.apply({}, args); |
1722 | } |
1723 | |
1724 | |
1725 | /************************************ |
1726 | Week of Year |
1727 | ************************************/ |
1728 | |
1729 | |
1730 | // firstDayOfWeek 0 = sun, 6 = sat |
1731 | // the day of the week that starts the week |
1732 | // (usually sunday or monday) |
1733 | // firstDayOfWeekOfYear 0 = sun, 6 = sat |
1734 | // the first week is the week that contains the first |
1735 | // of this day of the week |
1736 | // (eg. ISO weeks use thursday (4)) |
1737 | function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { |
1738 | var end = firstDayOfWeekOfYear - firstDayOfWeek, |
1739 | daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), |
1740 | adjustedMoment; |
1741 | |
1742 | |
1743 | if (daysToDayOfWeek > end) { |
1744 | daysToDayOfWeek -= 7; |
1745 | } |
1746 | |
1747 | if (daysToDayOfWeek < end - 7) { |
1748 | daysToDayOfWeek += 7; |
1749 | } |
1750 | |
1751 | adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd'); |
1752 | return { |
1753 | week: Math.ceil(adjustedMoment.dayOfYear() / 7), |
1754 | year: adjustedMoment.year() |
1755 | }; |
1756 | } |
1757 | |
1758 | //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday |
1759 | function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { |
1760 | var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; |
1761 | |
1762 | d = d === 0 ? 7 : d; |
1763 | weekday = weekday != null ? weekday : firstDayOfWeek; |
1764 | daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); |
1765 | dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; |
1766 | |
1767 | return { |
1768 | year: dayOfYear > 0 ? year : year - 1, |
1769 | dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear |
1770 | }; |
1771 | } |
1772 | |
1773 | /************************************ |
1774 | Top Level Functions |
1775 | ************************************/ |
1776 | |
1777 | function makeMoment(config) { |
1778 | var input = config._i, |
1779 | format = config._f, |
1780 | res; |
1781 | |
1782 | config._locale = config._locale || moment.localeData(config._l); |
1783 | |
1784 | if (input === null || (format === undefined && input === '')) { |
1785 | return moment.invalid({nullInput: true}); |
1786 | } |
1787 | |
1788 | if (typeof input === 'string') { |
1789 | config._i = input = config._locale.preparse(input); |
1790 | } |
1791 | |
1792 | if (moment.isMoment(input)) { |
1793 | return new Moment(input, true); |
1794 | } else if (format) { |
1795 | if (isArray(format)) { |
1796 | makeDateFromStringAndArray(config); |
1797 | } else { |
1798 | makeDateFromStringAndFormat(config); |
1799 | } |
1800 | } else { |
1801 | makeDateFromInput(config); |
1802 | } |
1803 | |
1804 | res = new Moment(config); |
1805 | if (res._nextDay) { |
1806 | // Adding is smart enough around DST |
1807 | res.add(1, 'd'); |
1808 | res._nextDay = undefined; |
1809 | } |
1810 | |
1811 | return res; |
1812 | } |
1813 | |
1814 | moment = function (input, format, locale, strict) { |
1815 | var c; |
1816 | |
1817 | if (typeof(locale) === 'boolean') { |
1818 | strict = locale; |
1819 | locale = undefined; |
1820 | } |
1821 | // object construction must be done this way. |
1822 | // https://github.com/moment/moment/issues/1423 |
1823 | c = {}; |
1824 | c._isAMomentObject = true; |
1825 | c._i = input; |
1826 | c._f = format; |
1827 | c._l = locale; |
1828 | c._strict = strict; |
1829 | c._isUTC = false; |
1830 | c._pf = defaultParsingFlags(); |
1831 | |
1832 | return makeMoment(c); |
1833 | }; |
1834 | |
1835 | moment.suppressDeprecationWarnings = false; |
1836 | |
1837 | moment.createFromInputFallback = deprecate( |
1838 | 'moment construction falls back to js Date. This is ' + |
1839 | 'discouraged and will be removed in upcoming major ' + |
1840 | 'release. Please refer to ' + |
1841 | 'https://github.com/moment/moment/issues/1407 for more info.', |
1842 | function (config) { |
1843 | config._d = new Date(config._i + (config._useUTC ? ' UTC' : '')); |
1844 | } |
1845 | ); |
1846 | |
1847 | // Pick a moment m from moments so that m[fn](other) is true for all |
1848 | // other. This relies on the function fn to be transitive. |
1849 | // |
1850 | // moments should either be an array of moment objects or an array, whose |
1851 | // first element is an array of moment objects. |
1852 | function pickBy(fn, moments) { |
1853 | var res, i; |
1854 | if (moments.length === 1 && isArray(moments[0])) { |
1855 | moments = moments[0]; |
1856 | } |
1857 | if (!moments.length) { |
1858 | return moment(); |
1859 | } |
1860 | res = moments[0]; |
1861 | for (i = 1; i < moments.length; ++i) { |
1862 | if (moments[i][fn](res)) { |
1863 | res = moments[i]; |
1864 | } |
1865 | } |
1866 | return res; |
1867 | } |
1868 | |
1869 | moment.min = function () { |
1870 | var args = [].slice.call(arguments, 0); |
1871 | |
1872 | return pickBy('isBefore', args); |
1873 | }; |
1874 | |
1875 | moment.max = function () { |
1876 | var args = [].slice.call(arguments, 0); |
1877 | |
1878 | return pickBy('isAfter', args); |
1879 | }; |
1880 | |
1881 | // creating with utc |
1882 | moment.utc = function (input, format, locale, strict) { |
1883 | var c; |
1884 | |
1885 | if (typeof(locale) === 'boolean') { |
1886 | strict = locale; |
1887 | locale = undefined; |
1888 | } |
1889 | // object construction must be done this way. |
1890 | // https://github.com/moment/moment/issues/1423 |
1891 | c = {}; |
1892 | c._isAMomentObject = true; |
1893 | c._useUTC = true; |
1894 | c._isUTC = true; |
1895 | c._l = locale; |
1896 | c._i = input; |
1897 | c._f = format; |
1898 | c._strict = strict; |
1899 | c._pf = defaultParsingFlags(); |
1900 | |
1901 | return makeMoment(c).utc(); |
1902 | }; |
1903 | |
1904 | // creating with unix timestamp (in seconds) |
1905 | moment.unix = function (input) { |
1906 | return moment(input * 1000); |
1907 | }; |
1908 | |
1909 | // duration |
1910 | moment.duration = function (input, key) { |
1911 | var duration = input, |
1912 | // matching against regexp is expensive, do it on demand |
1913 | match = null, |
1914 | sign, |
1915 | ret, |
1916 | parseIso, |
1917 | diffRes; |
1918 | |
1919 | if (moment.isDuration(input)) { |
1920 | duration = { |
1921 | ms: input._milliseconds, |
1922 | d: input._days, |
1923 | M: input._months |
1924 | }; |
1925 | } else if (typeof input === 'number') { |
1926 | duration = {}; |
1927 | if (key) { |
1928 | duration[key] = input; |
1929 | } else { |
1930 | duration.milliseconds = input; |
1931 | } |
1932 | } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { |
1933 | sign = (match[1] === '-') ? -1 : 1; |
1934 | duration = { |
1935 | y: 0, |
1936 | d: toInt(match[DATE]) * sign, |
1937 | h: toInt(match[HOUR]) * sign, |
1938 | m: toInt(match[MINUTE]) * sign, |
1939 | s: toInt(match[SECOND]) * sign, |
1940 | ms: toInt(match[MILLISECOND]) * sign |
1941 | }; |
1942 | } else if (!!(match = isoDurationRegex.exec(input))) { |
1943 | sign = (match[1] === '-') ? -1 : 1; |
1944 | parseIso = function (inp) { |
1945 | // We'd normally use ~~inp for this, but unfortunately it also |
1946 | // converts floats to ints. |
1947 | // inp may be undefined, so careful calling replace on it. |
1948 | var res = inp && parseFloat(inp.replace(',', '.')); |
1949 | // apply sign while we're at it |
1950 | return (isNaN(res) ? 0 : res) * sign; |
1951 | }; |
1952 | duration = { |
1953 | y: parseIso(match[2]), |
1954 | M: parseIso(match[3]), |
1955 | d: parseIso(match[4]), |
1956 | h: parseIso(match[5]), |
1957 | m: parseIso(match[6]), |
1958 | s: parseIso(match[7]), |
1959 | w: parseIso(match[8]) |
1960 | }; |
1961 | } else if (typeof duration === 'object' && |
1962 | ('from' in duration || 'to' in duration)) { |
1963 | diffRes = momentsDifference(moment(duration.from), moment(duration.to)); |
1964 | |
1965 | duration = {}; |
1966 | duration.ms = diffRes.milliseconds; |
1967 | duration.M = diffRes.months; |
1968 | } |
1969 | |
1970 | ret = new Duration(duration); |
1971 | |
1972 | if (moment.isDuration(input) && hasOwnProp(input, '_locale')) { |
1973 | ret._locale = input._locale; |
1974 | } |
1975 | |
1976 | return ret; |
1977 | }; |
1978 | |
1979 | // version number |
1980 | moment.version = VERSION; |
1981 | |
1982 | // default format |
1983 | moment.defaultFormat = isoFormat; |
1984 | |
1985 | // constant that refers to the ISO standard |
1986 | moment.ISO_8601 = function () {}; |
1987 | |
1988 | // Plugins that add properties should also add the key here (null value), |
1989 | // so we can properly clone ourselves. |
1990 | moment.momentProperties = momentProperties; |
1991 | |
1992 | // This function will be called whenever a moment is mutated. |
1993 | // It is intended to keep the offset in sync with the timezone. |
1994 | moment.updateOffset = function () {}; |
1995 | |
1996 | // This function allows you to set a threshold for relative time strings |
1997 | moment.relativeTimeThreshold = function (threshold, limit) { |
1998 | if (relativeTimeThresholds[threshold] === undefined) { |
1999 | return false; |
2000 | } |
2001 | if (limit === undefined) { |
2002 | return relativeTimeThresholds[threshold]; |
2003 | } |
2004 | relativeTimeThresholds[threshold] = limit; |
2005 | return true; |
2006 | }; |
2007 | |
2008 | moment.lang = deprecate( |
2009 | 'moment.lang is deprecated. Use moment.locale instead.', |
2010 | function (key, value) { |
2011 | return moment.locale(key, value); |
2012 | } |
2013 | ); |
2014 | |
2015 | // This function will load locale and then set the global locale. If |
2016 | // no arguments are passed in, it will simply return the current global |
2017 | // locale key. |
2018 | moment.locale = function (key, values) { |
2019 | var data; |
2020 | if (key) { |
2021 | if (typeof(values) !== 'undefined') { |
2022 | data = moment.defineLocale(key, values); |
2023 | } |
2024 | else { |
2025 | data = moment.localeData(key); |
2026 | } |
2027 | |
2028 | if (data) { |
2029 | moment.duration._locale = moment._locale = data; |
2030 | } |
2031 | } |
2032 | |
2033 | return moment._locale._abbr; |
2034 | }; |
2035 | |
2036 | moment.defineLocale = function (name, values) { |
2037 | if (values !== null) { |
2038 | values.abbr = name; |
2039 | if (!locales[name]) { |
2040 | locales[name] = new Locale(); |
2041 | } |
2042 | locales[name].set(values); |
2043 | |
2044 | // backwards compat for now: also set the locale |
2045 | moment.locale(name); |
2046 | |
2047 | return locales[name]; |
2048 | } else { |
2049 | // useful for testing |
2050 | delete locales[name]; |
2051 | return null; |
2052 | } |
2053 | }; |
2054 | |
2055 | moment.langData = deprecate( |
2056 | 'moment.langData is deprecated. Use moment.localeData instead.', |
2057 | function (key) { |
2058 | return moment.localeData(key); |
2059 | } |
2060 | ); |
2061 | |
2062 | // returns locale data |
2063 | moment.localeData = function (key) { |
2064 | var locale; |
2065 | |
2066 | if (key && key._locale && key._locale._abbr) { |
2067 | key = key._locale._abbr; |
2068 | } |
2069 | |
2070 | if (!key) { |
2071 | return moment._locale; |
2072 | } |
2073 | |
2074 | if (!isArray(key)) { |
2075 | //short-circuit everything else |
2076 | locale = loadLocale(key); |
2077 | if (locale) { |
2078 | return locale; |
2079 | } |
2080 | key = [key]; |
2081 | } |
2082 | |
2083 | return chooseLocale(key); |
2084 | }; |
2085 | |
2086 | // compare moment object |
2087 | moment.isMoment = function (obj) { |
2088 | return obj instanceof Moment || |
2089 | (obj != null && hasOwnProp(obj, '_isAMomentObject')); |
2090 | }; |
2091 | |
2092 | // for typechecking Duration objects |
2093 | moment.isDuration = function (obj) { |
2094 | return obj instanceof Duration; |
2095 | }; |
2096 | |
2097 | for (i = lists.length - 1; i >= 0; --i) { |
2098 | makeList(lists[i]); |
2099 | } |
2100 | |
2101 | moment.normalizeUnits = function (units) { |
2102 | return normalizeUnits(units); |
2103 | }; |
2104 | |
2105 | moment.invalid = function (flags) { |
2106 | var m = moment.utc(NaN); |
2107 | if (flags != null) { |
2108 | extend(m._pf, flags); |
2109 | } |
2110 | else { |
2111 | m._pf.userInvalidated = true; |
2112 | } |
2113 | |
2114 | return m; |
2115 | }; |
2116 | |
2117 | moment.parseZone = function () { |
2118 | return moment.apply(null, arguments).parseZone(); |
2119 | }; |
2120 | |
2121 | moment.parseTwoDigitYear = function (input) { |
2122 | return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); |
2123 | }; |
2124 | |
2125 | /************************************ |
2126 | Moment Prototype |
2127 | ************************************/ |
2128 | |
2129 | |
2130 | extend(moment.fn = Moment.prototype, { |
2131 | |
2132 | clone : function () { |
2133 | return moment(this); |
2134 | }, |
2135 | |
2136 | valueOf : function () { |
2137 | return +this._d + ((this._offset || 0) * 60000); |
2138 | }, |
2139 | |
2140 | unix : function () { |
2141 | return Math.floor(+this / 1000); |
2142 | }, |
2143 | |
2144 | toString : function () { |
2145 | return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); |
2146 | }, |
2147 | |
2148 | toDate : function () { |
2149 | return this._offset ? new Date(+this) : this._d; |
2150 | }, |
2151 | |
2152 | toISOString : function () { |
2153 | var m = moment(this).utc(); |
2154 | if (0 < m.year() && m.year() <= 9999) { |
2155 | if ('function' === typeof Date.prototype.toISOString) { |
2156 | // native implementation is ~50x faster, use it when we can |
2157 | return this.toDate().toISOString(); |
2158 | } else { |
2159 | return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); |
2160 | } |
2161 | } else { |
2162 | return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); |
2163 | } |
2164 | }, |
2165 | |
2166 | toArray : function () { |
2167 | var m = this; |
2168 | return [ |
2169 | m.year(), |
2170 | m.month(), |
2171 | m.date(), |
2172 | m.hours(), |
2173 | m.minutes(), |
2174 | m.seconds(), |
2175 | m.milliseconds() |
2176 | ]; |
2177 | }, |
2178 | |
2179 | isValid : function () { |
2180 | return isValid(this); |
2181 | }, |
2182 | |
2183 | isDSTShifted : function () { |
2184 | if (this._a) { |
2185 | return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; |
2186 | } |
2187 | |
2188 | return false; |
2189 | }, |
2190 | |
2191 | parsingFlags : function () { |
2192 | return extend({}, this._pf); |
2193 | }, |
2194 | |
2195 | invalidAt: function () { |
2196 | return this._pf.overflow; |
2197 | }, |
2198 | |
2199 | utc : function (keepLocalTime) { |
2200 | return this.zone(0, keepLocalTime); |
2201 | }, |
2202 | |
2203 | local : function (keepLocalTime) { |
2204 | if (this._isUTC) { |
2205 | this.zone(0, keepLocalTime); |
2206 | this._isUTC = false; |
2207 | |
2208 | if (keepLocalTime) { |
2209 | this.add(this._dateTzOffset(), 'm'); |
2210 | } |
2211 | } |
2212 | return this; |
2213 | }, |
2214 | |
2215 | format : function (inputString) { |
2216 | var output = formatMoment(this, inputString || moment.defaultFormat); |
2217 | return this.localeData().postformat(output); |
2218 | }, |
2219 | |
2220 | add : createAdder(1, 'add'), |
2221 | |
2222 | subtract : createAdder(-1, 'subtract'), |
2223 | |
2224 | diff : function (input, units, asFloat) { |
2225 | var that = makeAs(input, this), |
2226 | zoneDiff = (this.zone() - that.zone()) * 6e4, |
2227 | diff, output, daysAdjust; |
2228 | |
2229 | units = normalizeUnits(units); |
2230 | |
2231 | if (units === 'year' || units === 'month') { |
2232 | // average number of days in the months in the given dates |
2233 | diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 |
2234 | // difference in months |
2235 | output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); |
2236 | // adjust by taking difference in days, average number of days |
2237 | // and dst in the given months. |
2238 | daysAdjust = (this - moment(this).startOf('month')) - |
2239 | (that - moment(that).startOf('month')); |
2240 | // same as above but with zones, to negate all dst |
2241 | daysAdjust -= ((this.zone() - moment(this).startOf('month').zone()) - |
2242 | (that.zone() - moment(that).startOf('month').zone())) * 6e4; |
2243 | output += daysAdjust / diff; |
2244 | if (units === 'year') { |
2245 | output = output / 12; |
2246 | } |
2247 | } else { |
2248 | diff = (this - that); |
2249 | output = units === 'second' ? diff / 1e3 : // 1000 |
2250 | units === 'minute' ? diff / 6e4 : // 1000 * 60 |
2251 | units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 |
2252 | units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst |
2253 | units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst |
2254 | diff; |
2255 | } |
2256 | return asFloat ? output : absRound(output); |
2257 | }, |
2258 | |
2259 | from : function (time, withoutSuffix) { |
2260 | return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); |
2261 | }, |
2262 | |
2263 | fromNow : function (withoutSuffix) { |
2264 | return this.from(moment(), withoutSuffix); |
2265 | }, |
2266 | |
2267 | calendar : function (time) { |
2268 | // We want to compare the start of today, vs this. |
2269 | // Getting start-of-today depends on whether we're zone'd or not. |
2270 | var now = time || moment(), |
2271 | sod = makeAs(now, this).startOf('day'), |
2272 | diff = this.diff(sod, 'days', true), |
2273 | format = diff < -6 ? 'sameElse' : |
2274 | diff < -1 ? 'lastWeek' : |
2275 | diff < 0 ? 'lastDay' : |
2276 | diff < 1 ? 'sameDay' : |
2277 | diff < 2 ? 'nextDay' : |
2278 | diff < 7 ? 'nextWeek' : 'sameElse'; |
2279 | return this.format(this.localeData().calendar(format, this, moment(now))); |
2280 | }, |
2281 | |
2282 | isLeapYear : function () { |
2283 | return isLeapYear(this.year()); |
2284 | }, |
2285 | |
2286 | isDST : function () { |
2287 | return (this.zone() < this.clone().month(0).zone() || |
2288 | this.zone() < this.clone().month(5).zone()); |
2289 | }, |
2290 | |
2291 | day : function (input) { |
2292 | var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); |
2293 | if (input != null) { |
2294 | input = parseWeekday(input, this.localeData()); |
2295 | return this.add(input - day, 'd'); |
2296 | } else { |
2297 | return day; |
2298 | } |
2299 | }, |
2300 | |
2301 | month : makeAccessor('Month', true), |
2302 | |
2303 | startOf : function (units) { |
2304 | units = normalizeUnits(units); |
2305 | // the following switch intentionally omits break keywords |
2306 | // to utilize falling through the cases. |
2307 | switch (units) { |
2308 | case 'year': |
2309 | this.month(0); |
2310 | /* falls through */ |
2311 | case 'quarter': |
2312 | case 'month': |
2313 | this.date(1); |
2314 | /* falls through */ |
2315 | case 'week': |
2316 | case 'isoWeek': |
2317 | case 'day': |
2318 | this.hours(0); |
2319 | /* falls through */ |
2320 | case 'hour': |
2321 | this.minutes(0); |
2322 | /* falls through */ |
2323 | case 'minute': |
2324 | this.seconds(0); |
2325 | /* falls through */ |
2326 | case 'second': |
2327 | this.milliseconds(0); |
2328 | /* falls through */ |
2329 | } |
2330 | |
2331 | // weeks are a special case |
2332 | if (units === 'week') { |
2333 | this.weekday(0); |
2334 | } else if (units === 'isoWeek') { |
2335 | this.isoWeekday(1); |
2336 | } |
2337 | |
2338 | // quarters are also special |
2339 | if (units === 'quarter') { |
2340 | this.month(Math.floor(this.month() / 3) * 3); |
2341 | } |
2342 | |
2343 | return this; |
2344 | }, |
2345 | |
2346 | endOf: function (units) { |
2347 | units = normalizeUnits(units); |
2348 | if (units === undefined || units === 'millisecond') { |
2349 | return this; |
2350 | } |
2351 | return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); |
2352 | }, |
2353 | |
2354 | isAfter: function (input, units) { |
2355 | var inputMs; |
2356 | units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); |
2357 | if (units === 'millisecond') { |
2358 | input = moment.isMoment(input) ? input : moment(input); |
2359 | return +this > +input; |
2360 | } else { |
2361 | inputMs = moment.isMoment(input) ? +input : +moment(input); |
2362 | return inputMs < +this.clone().startOf(units); |
2363 | } |
2364 | }, |
2365 | |
2366 | isBefore: function (input, units) { |
2367 | var inputMs; |
2368 | units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); |
2369 | if (units === 'millisecond') { |
2370 | input = moment.isMoment(input) ? input : moment(input); |
2371 | return +this < +input; |
2372 | } else { |
2373 | inputMs = moment.isMoment(input) ? +input : +moment(input); |
2374 | return +this.clone().endOf(units) < inputMs; |
2375 | } |
2376 | }, |
2377 | |
2378 | isSame: function (input, units) { |
2379 | var inputMs; |
2380 | units = normalizeUnits(units || 'millisecond'); |
2381 | if (units === 'millisecond') { |
2382 | input = moment.isMoment(input) ? input : moment(input); |
2383 | return +this === +input; |
2384 | } else { |
2385 | inputMs = +moment(input); |
2386 | return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units)); |
2387 | } |
2388 | }, |
2389 | |
2390 | min: deprecate( |
2391 | 'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548', |
2392 | function (other) { |
2393 | other = moment.apply(null, arguments); |
2394 | return other < this ? this : other; |
2395 | } |
2396 | ), |
2397 | |
2398 | max: deprecate( |
2399 | 'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548', |
2400 | function (other) { |
2401 | other = moment.apply(null, arguments); |
2402 | return other > this ? this : other; |
2403 | } |
2404 | ), |
2405 | |
2406 | // keepLocalTime = true means only change the timezone, without |
2407 | // affecting the local hour. So 5:31:26 +0300 --[zone(2, true)]--> |
2408 | // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist int zone |
2409 | // +0200, so we adjust the time as needed, to be valid. |
2410 | // |
2411 | // Keeping the time actually adds/subtracts (one hour) |
2412 | // from the actual represented time. That is why we call updateOffset |
2413 | // a second time. In case it wants us to change the offset again |
2414 | // _changeInProgress == true case, then we have to adjust, because |
2415 | // there is no such time in the given timezone. |
2416 | zone : function (input, keepLocalTime) { |
2417 | var offset = this._offset || 0, |
2418 | localAdjust; |
2419 | if (input != null) { |
2420 | if (typeof input === 'string') { |
2421 | input = timezoneMinutesFromString(input); |
2422 | } |
2423 | if (Math.abs(input) < 16) { |
2424 | input = input * 60; |
2425 | } |
2426 | if (!this._isUTC && keepLocalTime) { |
2427 | localAdjust = this._dateTzOffset(); |
2428 | } |
2429 | this._offset = input; |
2430 | this._isUTC = true; |
2431 | if (localAdjust != null) { |
2432 | this.subtract(localAdjust, 'm'); |
2433 | } |
2434 | if (offset !== input) { |
2435 | if (!keepLocalTime || this._changeInProgress) { |
2436 | addOrSubtractDurationFromMoment(this, |
2437 | moment.duration(offset - input, 'm'), 1, false); |
2438 | } else if (!this._changeInProgress) { |
2439 | this._changeInProgress = true; |
2440 | moment.updateOffset(this, true); |
2441 | this._changeInProgress = null; |
2442 | } |
2443 | } |
2444 | } else { |
2445 | return this._isUTC ? offset : this._dateTzOffset(); |
2446 | } |
2447 | return this; |
2448 | }, |
2449 | |
2450 | zoneAbbr : function () { |
2451 | return this._isUTC ? 'UTC' : ''; |
2452 | }, |
2453 | |
2454 | zoneName : function () { |
2455 | return this._isUTC ? 'Coordinated Universal Time' : ''; |
2456 | }, |
2457 | |
2458 | parseZone : function () { |
2459 | if (this._tzm) { |
2460 | this.zone(this._tzm); |
2461 | } else if (typeof this._i === 'string') { |
2462 | this.zone(this._i); |
2463 | } |
2464 | return this; |
2465 | }, |
2466 | |
2467 | hasAlignedHourOffset : function (input) { |
2468 | if (!input) { |
2469 | input = 0; |
2470 | } |
2471 | else { |
2472 | input = moment(input).zone(); |
2473 | } |
2474 | |
2475 | return (this.zone() - input) % 60 === 0; |
2476 | }, |
2477 | |
2478 | daysInMonth : function () { |
2479 | return daysInMonth(this.year(), this.month()); |
2480 | }, |
2481 | |
2482 | dayOfYear : function (input) { |
2483 | var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; |
2484 | return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); |
2485 | }, |
2486 | |
2487 | quarter : function (input) { |
2488 | return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); |
2489 | }, |
2490 | |
2491 | weekYear : function (input) { |
2492 | var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; |
2493 | return input == null ? year : this.add((input - year), 'y'); |
2494 | }, |
2495 | |
2496 | isoWeekYear : function (input) { |
2497 | var year = weekOfYear(this, 1, 4).year; |
2498 | return input == null ? year : this.add((input - year), 'y'); |
2499 | }, |
2500 | |
2501 | week : function (input) { |
2502 | var week = this.localeData().week(this); |
2503 | return input == null ? week : this.add((input - week) * 7, 'd'); |
2504 | }, |
2505 | |
2506 | isoWeek : function (input) { |
2507 | var week = weekOfYear(this, 1, 4).week; |
2508 | return input == null ? week : this.add((input - week) * 7, 'd'); |
2509 | }, |
2510 | |
2511 | weekday : function (input) { |
2512 | var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; |
2513 | return input == null ? weekday : this.add(input - weekday, 'd'); |
2514 | }, |
2515 | |
2516 | isoWeekday : function (input) { |
2517 | // behaves the same as moment#day except |
2518 | // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) |
2519 | // as a setter, sunday should belong to the previous week. |
2520 | return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); |
2521 | }, |
2522 | |
2523 | isoWeeksInYear : function () { |
2524 | return weeksInYear(this.year(), 1, 4); |
2525 | }, |
2526 | |
2527 | weeksInYear : function () { |
2528 | var weekInfo = this.localeData()._week; |
2529 | return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); |
2530 | }, |
2531 | |
2532 | get : function (units) { |
2533 | units = normalizeUnits(units); |
2534 | return this[units](); |
2535 | }, |
2536 | |
2537 | set : function (units, value) { |
2538 | units = normalizeUnits(units); |
2539 | if (typeof this[units] === 'function') { |
2540 | this[units](value); |
2541 | } |
2542 | return this; |
2543 | }, |
2544 | |
2545 | // If passed a locale key, it will set the locale for this |
2546 | // instance. Otherwise, it will return the locale configuration |
2547 | // variables for this instance. |
2548 | locale : function (key) { |
2549 | var newLocaleData; |
2550 | |
2551 | if (key === undefined) { |
2552 | return this._locale._abbr; |
2553 | } else { |
2554 | newLocaleData = moment.localeData(key); |
2555 | if (newLocaleData != null) { |
2556 | this._locale = newLocaleData; |
2557 | } |
2558 | return this; |
2559 | } |
2560 | }, |
2561 | |
2562 | lang : deprecate( |
2563 | 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', |
2564 | function (key) { |
2565 | if (key === undefined) { |
2566 | return this.localeData(); |
2567 | } else { |
2568 | return this.locale(key); |
2569 | } |
2570 | } |
2571 | ), |
2572 | |
2573 | localeData : function () { |
2574 | return this._locale; |
2575 | }, |
2576 | |
2577 | _dateTzOffset : function () { |
2578 | // On Firefox.24 Date#getTimezoneOffset returns a floating point. |
2579 | // https://github.com/moment/moment/pull/1871 |
2580 | return Math.round(this._d.getTimezoneOffset() / 15) * 15; |
2581 | } |
2582 | }); |
2583 | |
2584 | function rawMonthSetter(mom, value) { |
2585 | var dayOfMonth; |
2586 | |
2587 | // TODO: Move this out of here! |
2588 | if (typeof value === 'string') { |
2589 | value = mom.localeData().monthsParse(value); |
2590 | // TODO: Another silent failure? |
2591 | if (typeof value !== 'number') { |
2592 | return mom; |
2593 | } |
2594 | } |
2595 | |
2596 | dayOfMonth = Math.min(mom.date(), |
2597 | daysInMonth(mom.year(), value)); |
2598 | mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); |
2599 | return mom; |
2600 | } |
2601 | |
2602 | function rawGetter(mom, unit) { |
2603 | return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); |
2604 | } |
2605 | |
2606 | function rawSetter(mom, unit, value) { |
2607 | if (unit === 'Month') { |
2608 | return rawMonthSetter(mom, value); |
2609 | } else { |
2610 | return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); |
2611 | } |
2612 | } |
2613 | |
2614 | function makeAccessor(unit, keepTime) { |
2615 | return function (value) { |
2616 | if (value != null) { |
2617 | rawSetter(this, unit, value); |
2618 | moment.updateOffset(this, keepTime); |
2619 | return this; |
2620 | } else { |
2621 | return rawGetter(this, unit); |
2622 | } |
2623 | }; |
2624 | } |
2625 | |
2626 | moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false); |
2627 | moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false); |
2628 | moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false); |
2629 | // Setting the hour should keep the time, because the user explicitly |
2630 | // specified which hour he wants. So trying to maintain the same hour (in |
2631 | // a new timezone) makes sense. Adding/subtracting hours does not follow |
2632 | // this rule. |
2633 | moment.fn.hour = moment.fn.hours = makeAccessor('Hours', true); |
2634 | // moment.fn.month is defined separately |
2635 | moment.fn.date = makeAccessor('Date', true); |
2636 | moment.fn.dates = deprecate('dates accessor is deprecated. Use date instead.', makeAccessor('Date', true)); |
2637 | moment.fn.year = makeAccessor('FullYear', true); |
2638 | moment.fn.years = deprecate('years accessor is deprecated. Use year instead.', makeAccessor('FullYear', true)); |
2639 | |
2640 | // add plural methods |
2641 | moment.fn.days = moment.fn.day; |
2642 | moment.fn.months = moment.fn.month; |
2643 | moment.fn.weeks = moment.fn.week; |
2644 | moment.fn.isoWeeks = moment.fn.isoWeek; |
2645 | moment.fn.quarters = moment.fn.quarter; |
2646 | |
2647 | // add aliased format methods |
2648 | moment.fn.toJSON = moment.fn.toISOString; |
2649 | |
2650 | /************************************ |
2651 | Duration Prototype |
2652 | ************************************/ |
2653 | |
2654 | |
2655 | function daysToYears (days) { |
2656 | // 400 years have 146097 days (taking into account leap year rules) |
2657 | return days * 400 / 146097; |
2658 | } |
2659 | |
2660 | function yearsToDays (years) { |
2661 | // years * 365 + absRound(years / 4) - |
2662 | // absRound(years / 100) + absRound(years / 400); |
2663 | return years * 146097 / 400; |
2664 | } |
2665 | |
2666 | extend(moment.duration.fn = Duration.prototype, { |
2667 | |
2668 | _bubble : function () { |
2669 | var milliseconds = this._milliseconds, |
2670 | days = this._days, |
2671 | months = this._months, |
2672 | data = this._data, |
2673 | seconds, minutes, hours, years = 0; |
2674 | |
2675 | // The following code bubbles up values, see the tests for |
2676 | // examples of what that means. |
2677 | data.milliseconds = milliseconds % 1000; |
2678 | |
2679 | seconds = absRound(milliseconds / 1000); |
2680 | data.seconds = seconds % 60; |
2681 | |
2682 | minutes = absRound(seconds / 60); |
2683 | data.minutes = minutes % 60; |
2684 | |
2685 | hours = absRound(minutes / 60); |
2686 | data.hours = hours % 24; |
2687 | |
2688 | days += absRound(hours / 24); |
2689 | |
2690 | // Accurately convert days to years, assume start from year 0. |
2691 | years = absRound(daysToYears(days)); |
2692 | days -= absRound(yearsToDays(years)); |
2693 | |
2694 | // 30 days to a month |
2695 | // TODO (iskren): Use anchor date (like 1st Jan) to compute this. |
2696 | months += absRound(days / 30); |
2697 | days %= 30; |
2698 | |
2699 | // 12 months -> 1 year |
2700 | years += absRound(months / 12); |
2701 | months %= 12; |
2702 | |
2703 | data.days = days; |
2704 | data.months = months; |
2705 | data.years = years; |
2706 | }, |
2707 | |
2708 | abs : function () { |
2709 | this._milliseconds = Math.abs(this._milliseconds); |
2710 | this._days = Math.abs(this._days); |
2711 | this._months = Math.abs(this._months); |
2712 | |
2713 | this._data.milliseconds = Math.abs(this._data.milliseconds); |
2714 | this._data.seconds = Math.abs(this._data.seconds); |
2715 | this._data.minutes = Math.abs(this._data.minutes); |
2716 | this._data.hours = Math.abs(this._data.hours); |
2717 | this._data.months = Math.abs(this._data.months); |
2718 | this._data.years = Math.abs(this._data.years); |
2719 | |
2720 | return this; |
2721 | }, |
2722 | |
2723 | weeks : function () { |
2724 | return absRound(this.days() / 7); |
2725 | }, |
2726 | |
2727 | valueOf : function () { |
2728 | return this._milliseconds + |
2729 | this._days * 864e5 + |
2730 | (this._months % 12) * 2592e6 + |
2731 | toInt(this._months / 12) * 31536e6; |
2732 | }, |
2733 | |
2734 | humanize : function (withSuffix) { |
2735 | var output = relativeTime(this, !withSuffix, this.localeData()); |
2736 | |
2737 | if (withSuffix) { |
2738 | output = this.localeData().pastFuture(+this, output); |
2739 | } |
2740 | |
2741 | return this.localeData().postformat(output); |
2742 | }, |
2743 | |
2744 | add : function (input, val) { |
2745 | // supports only 2.0-style add(1, 's') or add(moment) |
2746 | var dur = moment.duration(input, val); |
2747 | |
2748 | this._milliseconds += dur._milliseconds; |
2749 | this._days += dur._days; |
2750 | this._months += dur._months; |
2751 | |
2752 | this._bubble(); |
2753 | |
2754 | return this; |
2755 | }, |
2756 | |
2757 | subtract : function (input, val) { |
2758 | var dur = moment.duration(input, val); |
2759 | |
2760 | this._milliseconds -= dur._milliseconds; |
2761 | this._days -= dur._days; |
2762 | this._months -= dur._months; |
2763 | |
2764 | this._bubble(); |
2765 | |
2766 | return this; |
2767 | }, |
2768 | |
2769 | get : function (units) { |
2770 | units = normalizeUnits(units); |
2771 | return this[units.toLowerCase() + 's'](); |
2772 | }, |
2773 | |
2774 | as : function (units) { |
2775 | var days, months; |
2776 | units = normalizeUnits(units); |
2777 | |
2778 | if (units === 'month' || units === 'year') { |
2779 | days = this._days + this._milliseconds / 864e5; |
2780 | months = this._months + daysToYears(days) * 12; |
2781 | return units === 'month' ? months : months / 12; |
2782 | } else { |
2783 | // handle milliseconds separately because of floating point math errors (issue #1867) |
2784 | days = this._days + Math.round(yearsToDays(this._months / 12)); |
2785 | switch (units) { |
2786 | case 'week': return days / 7 + this._milliseconds / 6048e5; |
2787 | case 'day': return days + this._milliseconds / 864e5; |
2788 | case 'hour': return days * 24 + this._milliseconds / 36e5; |
2789 | case 'minute': return days * 24 * 60 + this._milliseconds / 6e4; |
2790 | case 'second': return days * 24 * 60 * 60 + this._milliseconds / 1000; |
2791 | // Math.floor prevents floating point math errors here |
2792 | case 'millisecond': return Math.floor(days * 24 * 60 * 60 * 1000) + this._milliseconds; |
2793 | default: throw new Error('Unknown unit ' + units); |
2794 | } |
2795 | } |
2796 | }, |
2797 | |
2798 | lang : moment.fn.lang, |
2799 | locale : moment.fn.locale, |
2800 | |
2801 | toIsoString : deprecate( |
2802 | 'toIsoString() is deprecated. Please use toISOString() instead ' + |
2803 | '(notice the capitals)', |
2804 | function () { |
2805 | return this.toISOString(); |
2806 | } |
2807 | ), |
2808 | |
2809 | toISOString : function () { |
2810 | // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js |
2811 | var years = Math.abs(this.years()), |
2812 | months = Math.abs(this.months()), |
2813 | days = Math.abs(this.days()), |
2814 | hours = Math.abs(this.hours()), |
2815 | minutes = Math.abs(this.minutes()), |
2816 | seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); |
2817 | |
2818 | if (!this.asSeconds()) { |
2819 | // this is the same as C#'s (Noda) and python (isodate)... |
2820 | // but not other JS (goog.date) |
2821 | return 'P0D'; |
2822 | } |
2823 | |
2824 | return (this.asSeconds() < 0 ? '-' : '') + |
2825 | 'P' + |
2826 | (years ? years + 'Y' : '') + |
2827 | (months ? months + 'M' : '') + |
2828 | (days ? days + 'D' : '') + |
2829 | ((hours || minutes || seconds) ? 'T' : '') + |
2830 | (hours ? hours + 'H' : '') + |
2831 | (minutes ? minutes + 'M' : '') + |
2832 | (seconds ? seconds + 'S' : ''); |
2833 | }, |
2834 | |
2835 | localeData : function () { |
2836 | return this._locale; |
2837 | } |
2838 | }); |
2839 | |
2840 | moment.duration.fn.toString = moment.duration.fn.toISOString; |
2841 | |
2842 | function makeDurationGetter(name) { |
2843 | moment.duration.fn[name] = function () { |
2844 | return this._data[name]; |
2845 | }; |
2846 | } |
2847 | |
2848 | for (i in unitMillisecondFactors) { |
2849 | if (hasOwnProp(unitMillisecondFactors, i)) { |
2850 | makeDurationGetter(i.toLowerCase()); |
2851 | } |
2852 | } |
2853 | |
2854 | moment.duration.fn.asMilliseconds = function () { |
2855 | return this.as('ms'); |
2856 | }; |
2857 | moment.duration.fn.asSeconds = function () { |
2858 | return this.as('s'); |
2859 | }; |
2860 | moment.duration.fn.asMinutes = function () { |
2861 | return this.as('m'); |
2862 | }; |
2863 | moment.duration.fn.asHours = function () { |
2864 | return this.as('h'); |
2865 | }; |
2866 | moment.duration.fn.asDays = function () { |
2867 | return this.as('d'); |
2868 | }; |
2869 | moment.duration.fn.asWeeks = function () { |
2870 | return this.as('weeks'); |
2871 | }; |
2872 | moment.duration.fn.asMonths = function () { |
2873 | return this.as('M'); |
2874 | }; |
2875 | moment.duration.fn.asYears = function () { |
2876 | return this.as('y'); |
2877 | }; |
2878 | |
2879 | /************************************ |
2880 | Default Locale |
2881 | ************************************/ |
2882 | |
2883 | |
2884 | // Set default locale, other locale will inherit from English. |
2885 | moment.locale('en', { |
2886 | ordinalParse: /\d{1,2}(th|st|nd|rd)/, |
2887 | ordinal : function (number) { |
2888 | var b = number % 10, |
2889 | output = (toInt(number % 100 / 10) === 1) ? 'th' : |
2890 | (b === 1) ? 'st' : |
2891 | (b === 2) ? 'nd' : |
2892 | (b === 3) ? 'rd' : 'th'; |
2893 | return number + output; |
2894 | } |
2895 | }); |
2896 | |
2897 | /* EMBED_LOCALES */ |
2898 | |
2899 | /************************************ |
2900 | Exposing Moment |
2901 | ************************************/ |
2902 | |
2903 | function makeGlobal(shouldDeprecate) { |
2904 | /*global ender:false */ |
2905 | if (typeof ender !== 'undefined') { |
2906 | return; |
2907 | } |
2908 | oldGlobalMoment = globalScope.moment; |
2909 | if (shouldDeprecate) { |
2910 | globalScope.moment = deprecate( |
2911 | 'Accessing Moment through the global scope is ' + |
2912 | 'deprecated, and will be removed in an upcoming ' + |
2913 | 'release.', |
2914 | moment); |
2915 | } else { |
2916 | globalScope.moment = moment; |
2917 | } |
2918 | } |
2919 | |
2920 | // CommonJS module is defined |
2921 | if (hasModule) { |
2922 | module.exports = moment; |
2923 | } else if (typeof define === 'function' && define.amd) { |
2924 | define('moment', function (require, exports, module) { |
2925 | if (module.config && module.config() && module.config().noGlobal === true) { |
2926 | // release the global variable |
2927 | globalScope.moment = oldGlobalMoment; |
2928 | } |
2929 | |
2930 | return moment; |
2931 | }); |
2932 | makeGlobal(true); |
2933 | } else { |
2934 | makeGlobal(); |
2935 | } |
2936 | }).call(this); |