timespan 0.5.2 → 0.5.3

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