client/js/datetime/momentjs/momentjs.js in rsence-pre-3.0.0.8 vs client/js/datetime/momentjs/momentjs.js in rsence-pre-3.0.0.9

- old
+ new

@@ -19,13 +19,14 @@ // check for nodeJS hasModule = (typeof module !== 'undefined' && module.exports), // ASP.NET json date format regex aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, + aspNetTimeSpanJsonRegex = /(\-)?(\d*)?\.?(\d+)\:(\d+)\:(\d+)\.?(\d{3})?/, // format tokens - formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g, + formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g, localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g, // parsing tokens parseMultipleFormatChunker = /([0-9a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)/gi, @@ -33,11 +34,11 @@ parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 parseTokenThreeDigits = /\d{3}/, // 000 - 999 parseTokenFourDigits = /\d{1,4}/, // 0 - 9999 parseTokenSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 - parseTokenWord = /[0-9]*[a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF]+\s*?[\u0600-\u06FF]+/i, // any word (or two) characters or numbers including two word month in arabic. + 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. parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z parseTokenT = /T/i, // T (ISO seperator) parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 // preliminary iso regex @@ -55,21 +56,32 @@ // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"] parseTimezoneChunker = /([\+\-]|\d\d)/gi, // getter and setter names - proxyGettersAndSetters = 'Month|Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), + proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), unitMillisecondFactors = { 'Milliseconds' : 1, 'Seconds' : 1e3, 'Minutes' : 6e4, 'Hours' : 36e5, 'Days' : 864e5, 'Months' : 2592e6, 'Years' : 31536e6 }, + unitAliases = { + ms : 'millisecond', + s : 'second', + m : 'minute', + h : 'hour', + d : 'day', + w : 'week', + M : 'month', + y : 'year' + }, + // format function strings formatFunctions = {}, // tokens to ordinalize and pad ordinalizeTokens = 'DDD w W M D d'.split(' '), @@ -116,10 +128,34 @@ return leftZeroFill(this.year(), 4); }, YYYYY : function () { return leftZeroFill(this.year(), 5); }, + gg : function () { + return leftZeroFill(this.weekYear() % 100, 2); + }, + gggg : function () { + return this.weekYear(); + }, + ggggg : function () { + return leftZeroFill(this.weekYear(), 5); + }, + GG : function () { + return leftZeroFill(this.isoWeekYear() % 100, 2); + }, + GGGG : function () { + return this.isoWeekYear(); + }, + GGGGG : function () { + return leftZeroFill(this.isoWeekYear(), 5); + }, + e : function () { + return this.weekday(); + }, + E : function () { + return this.isoWeekday(); + }, a : function () { return this.lang().meridiem(this.hours(), this.minutes(), true); }, A : function () { return this.lang().meridiem(this.hours(), this.minutes(), false); @@ -161,29 +197,35 @@ a = -a; b = "-"; } return b + leftZeroFill(~~(10 * a / 6), 4); }, + z : function () { + return this.zoneAbbr(); + }, + zz : function () { + return this.zoneName(); + }, X : function () { return this.unix(); } }; function padToken(func, count) { return function (a) { return leftZeroFill(func.call(this, a), count); }; } - function ordinalizeToken(func) { + function ordinalizeToken(func, period) { return function (a) { - return this.lang().ordinal(func.call(this, a)); + return this.lang().ordinal(func.call(this, a), period); }; } while (ordinalizeTokens.length) { i = ordinalizeTokens.pop(); - formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i]); + formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); } while (paddedTokens.length) { i = paddedTokens.pop(); formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); } @@ -287,28 +329,43 @@ } return output; } // helper function for _.addTime and _.subtractTime - function addOrSubtractDurationFromMoment(mom, duration, isAdding) { - var ms = duration._milliseconds, - d = duration._days, - M = duration._months, + function addOrSubtractDurationFromMoment(mom, duration, isAdding, ignoreUpdateOffset) { + var milliseconds = duration._milliseconds, + days = duration._days, + months = duration._months, + minutes, + hours, currentDate; - if (ms) { - mom._d.setTime(+mom + ms * isAdding); + if (milliseconds) { + mom._d.setTime(+mom._d + milliseconds * isAdding); } - if (d) { - mom.date(mom.date() + d * isAdding); + // store the minutes and hours so we can restore them + if (days || months) { + minutes = mom.minute(); + hours = mom.hour(); } - if (M) { + if (days) { + mom.date(mom.date() + days * isAdding); + } + if (months) { currentDate = mom.date(); mom.date(1) - .month(mom.month() + M * isAdding) + .month(mom.month() + months * isAdding) .date(Math.min(currentDate, mom.daysInMonth())); } + if (milliseconds && !ignoreUpdateOffset) { + moment.updateOffset(mom); + } + // restore the minutes and hours after possibly changing dst + if (days || months) { + mom.minute(minutes); + mom.hour(hours); + } } // check if is an array function isArray(input) { return Object.prototype.toString.call(input) === '[object Array]'; @@ -326,11 +383,15 @@ } } return diffs + lengthDiff; } + function normalizeUnits(units) { + return units ? unitAliases[units] || units.toLowerCase().replace(/(.)s$/, '$1') : units; + } + /************************************ Languages ************************************/ @@ -356,11 +417,11 @@ monthsShort : function (m) { return this._monthsShort[m.month()]; }, monthsParse : function (monthName) { - var i, mom, regex, output; + var i, mom, regex; if (!this._monthsParse) { this._monthsParse = []; } @@ -391,10 +452,31 @@ _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), weekdaysMin : function (m) { return this._weekdaysMin[m.day()]; }, + weekdaysParse : function (weekdayName) { + var i, mom, regex; + + if (!this._weekdaysParse) { + this._weekdaysParse = []; + } + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + if (!this._weekdaysParse[i]) { + mom = moment([2000, 1]).day(i); + regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + }, + _longDateFormat : { LT : "h:mm A", L : "MM/DD/YYYY", LL : "MMMM D YYYY", LLL : "MMMM D YYYY LT", @@ -409,10 +491,15 @@ this._longDateFormat[key] = output; } return output; }, + isPM : function (input) { + return ((input + '').toLowerCase()[0] === 'p'); + }, + + _meridiemParse : /[ap]\.?m?\.?/i, meridiem : function (hours, minutes, isLower) { if (hours > 11) { return isLower ? 'pm' : 'PM'; } else { return isLower ? 'am' : 'AM'; @@ -422,11 +509,11 @@ _calendar : { sameDay : '[Today at] LT', nextDay : '[Tomorrow at] LT', nextWeek : 'dddd [at] LT', lastDay : '[Yesterday at] LT', - lastWeek : '[last] dddd [at] LT', + lastWeek : '[Last] dddd [at] LT', sameElse : 'L' }, calendar : function (key, mom) { var output = this._calendar[key]; return typeof output === 'function' ? output.apply(mom) : output; @@ -470,11 +557,11 @@ postformat : function (string) { return string; }, week : function (mom) { - return weekOfYear(mom, this._week.dow, this._week.doy); + return weekOfYear(mom, this._week.dow, this._week.doy).week; }, _week : { dow : 0, // Sunday is the first day of the week. doy : 6 // The week that contains Jan 1st is the first week of the year. } @@ -534,11 +621,11 @@ } return function (mom) { var output = ""; for (i = 0; i < length; i++) { - output += typeof array[i].call === 'function' ? array[i].call(mom, format) : array[i]; + output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; } return output; }; } @@ -566,11 +653,11 @@ Parsing ************************************/ // get the regex to find the next token - function getParseRegexForToken(token) { + function getParseRegexForToken(token, config) { switch (token) { case 'DDDD': return parseTokenThreeDigits; case 'YYYY': return parseTokenFourDigits; @@ -584,13 +671,14 @@ case 'MMM': case 'MMMM': case 'dd': case 'ddd': case 'dddd': + return parseTokenWord; case 'a': case 'A': - return parseTokenWord; + return getLangDefinition(config._l)._meridiemParse; case 'X': return parseTokenTimestampMs; case 'Z': case 'ZZ': return parseTokenTimezone; @@ -614,10 +702,18 @@ default : return new RegExp(token.replace('\\', '')); } } + function timezoneMinutesFromString(string) { + var tzchunk = (parseTokenTimezone.exec(string) || [])[0], + parts = (tzchunk + '').match(parseTimezoneChunker) || ['-', 0, 0], + minutes = +(parts[1] * 60) + ~~parts[2]; + + return parts[0] === '+' ? -minutes : minutes; + } + // function to convert string input to date function addTimeToArrayFromToken(token, input, config) { var a, b, datePartArray = config._a; @@ -655,11 +751,11 @@ datePartArray[0] = ~~input; break; // AM / PM case 'a' : // fall through to A case 'A' : - config._isPm = ((input + '').toLowerCase() === 'pm'); + config._isPm = getLangDefinition(config._l).isPM(input); break; // 24 HOUR case 'H' : // fall through to hh case 'HH' : // fall through to hh case 'h' : // fall through to hh @@ -688,22 +784,11 @@ break; // TIMEZONE case 'Z' : // fall through to ZZ case 'ZZ' : config._useUTC = true; - a = (input + '').match(parseTimezoneChunker); - if (a && a[1]) { - config._tzh = ~~a[1]; - } - if (a && a[2]) { - config._tzm = ~~a[2]; - } - // reverse offsets - if (a && a[0] === '+') { - config._tzh = -config._tzh; - config._tzm = -config._tzm; - } + config._tzm = timezoneMinutesFromString(input); break; } // if the input is null, the date is not valid if (input == null) { @@ -725,12 +810,12 @@ for (i = 0; i < 7; i++) { config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; } // add the offsets to the time to be parsed so that we can have a clean array for checking isValid - input[3] += config._tzh || 0; - input[4] += config._tzm || 0; + input[3] += ~~((config._tzm || 0) / 60); + input[4] += ~~((config._tzm || 0) % 60); date = new Date(0); if (config._useUTC) { date.setUTCFullYear(input[0], input[1], input[2]); @@ -751,19 +836,25 @@ i, parsedInput; config._a = []; for (i = 0; i < tokens.length; i++) { - parsedInput = (getParseRegexForToken(tokens[i]).exec(string) || [])[0]; + parsedInput = (getParseRegexForToken(tokens[i], config).exec(string) || [])[0]; if (parsedInput) { string = string.slice(string.indexOf(parsedInput) + parsedInput.length); } // don't parse if its not a known token if (formatTokenFunctions[tokens[i]]) { addTimeToArrayFromToken(tokens[i], parsedInput, config); } } + + // add remaining unparsed input to the string + if (string) { + config._il = string; + } + // handle am pm if (config._isPm && config._a[3] < 12) { config._a[3] += 12; } // if is 12 am, change hours to 0 @@ -780,26 +871,26 @@ tempMoment, bestMoment, scoreToBeat = 99, i, - currentDate, currentScore; - while (config._f.length) { + for (i = 0; i < config._f.length; i++) { tempConfig = extend({}, config); - tempConfig._f = config._f.pop(); + tempConfig._f = config._f[i]; makeDateFromStringAndFormat(tempConfig); tempMoment = new Moment(tempConfig); - if (tempMoment.isValid()) { - bestMoment = tempMoment; - break; - } - currentScore = compareArrays(tempConfig._a, tempMoment.toArray()); + // if there is any input that was not parsed + // add a penalty for that format + if (tempMoment._il) { + currentScore += tempMoment._il.length; + } + if (currentScore < scoreToBeat) { scoreToBeat = currentScore; bestMoment = tempMoment; } } @@ -808,13 +899,16 @@ } // date from iso format function makeDateFromString(config) { var i, - string = config._i; - if (isoRegex.exec(string)) { - config._f = 'YYYY-MM-DDT'; + string = config._i, + match = isoRegex.exec(string); + + if (match) { + // match[2] should be "T" or undefined + config._f = 'YYYY-MM-DD' + (match[2] || " "); for (i = 0; i < 4; i++) { if (isoTimes[i][1].exec(string)) { config._f += isoTimes[i][0]; break; } @@ -892,22 +986,27 @@ // the first week is the week that contains the first // of this day of the week // (eg. ISO weeks use thursday (4)) function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { var end = firstDayOfWeekOfYear - firstDayOfWeek, - daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(); + daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), + adjustedMoment; if (daysToDayOfWeek > end) { daysToDayOfWeek -= 7; } if (daysToDayOfWeek < end - 7) { daysToDayOfWeek += 7; } - return Math.ceil(moment(mom).add('d', daysToDayOfWeek).dayOfYear() / 7); + adjustedMoment = moment(mom).add('d', daysToDayOfWeek); + return { + week: Math.ceil(adjustedMoment.dayOfYear() / 7), + year: adjustedMoment.year() + }; } /************************************ Top Level Functions @@ -969,18 +1068,30 @@ // duration moment.duration = function (input, key) { var isDuration = moment.isDuration(input), isNumber = (typeof input === 'number'), duration = (isDuration ? input._data : (isNumber ? {} : input)), + matched = aspNetTimeSpanJsonRegex.exec(input), + sign, ret; if (isNumber) { if (key) { duration[key] = input; } else { duration.milliseconds = input; } + } else if (matched) { + sign = (matched[1] === "-") ? -1 : 1; + duration = { + y: 0, + d: ~~matched[2] * sign, + h: ~~matched[3] * sign, + m: ~~matched[4] * sign, + s: ~~matched[5] * sign, + ms: ~~matched[6] * sign + }; } ret = new Duration(duration); if (isDuration && input.hasOwnProperty('_lang')) { @@ -994,10 +1105,14 @@ moment.version = VERSION; // default format moment.defaultFormat = isoFormat; + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + moment.updateOffset = function () {}; + // This function will load languages and then set the global language. If // no arguments are passed in, it will simply return the current global // language key. moment.lang = function (key, values) { var i; @@ -1042,27 +1157,27 @@ clone : function () { return moment(this); }, valueOf : function () { - return +this._d; + return +this._d + ((this._offset || 0) * 60000); }, unix : function () { - return Math.floor(+this._d / 1000); + return Math.floor(+this / 1000); }, toString : function () { return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); }, toDate : function () { - return this._d; + return this._offset ? new Date(+this) : this._d; }, - toJSON : function () { - return moment.utc(this).format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + toISOString : function () { + return formatMoment(moment(this).utc(), 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); }, toArray : function () { var m = this; return [ @@ -1086,15 +1201,15 @@ } return !!this._isValid; }, utc : function () { - this._isUTC = true; - return this; + return this.zone(0); }, local : function () { + this.zone(0); this._isUTC = false; return this; }, format : function (inputString) { @@ -1125,18 +1240,15 @@ addOrSubtractDurationFromMoment(this, dur, -1); return this; }, diff : function (input, units, asFloat) { - var that = this._isUTC ? moment(input).utc() : moment(input).local(), + var that = this._isUTC ? moment(input).zone(this._offset || 0) : moment(input).local(), zoneDiff = (this.zone() - that.zone()) * 6e4, diff, output; - if (units) { - // standardize on singular form - units = units.replace(/s$/, ''); - } + units = normalizeUnits(units); if (units === 'year' || units === 'month') { diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); output += ((this - moment(this).startOf('month')) - (that - moment(that).startOf('month'))) / diff; @@ -1178,22 +1290,48 @@ var year = this.year(); return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; }, isDST : function () { - return (this.zone() < moment([this.year()]).zone() || - this.zone() < moment([this.year(), 5]).zone()); + return (this.zone() < this.clone().month(0).zone() || + this.zone() < this.clone().month(5).zone()); }, day : function (input) { var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); - return input == null ? day : - this.add({ d : input - day }); + if (input != null) { + if (typeof input === 'string') { + input = this.lang().weekdaysParse(input); + if (typeof input !== 'number') { + return this; + } + } + return this.add({ d : input - day }); + } else { + return day; + } }, + month : function (input) { + var utc = this._isUTC ? 'UTC' : ''; + if (input != null) { + if (typeof input === 'string') { + input = this.lang().monthsParse(input); + if (typeof input !== 'number') { + return this; + } + } + this._d['set' + utc + 'Month'](input); + moment.updateOffset(this); + return this; + } else { + return this._d['get' + utc + 'Month'](); + } + }, + startOf: function (units) { - units = units.replace(/s$/, ''); + units = normalizeUnits(units); // the following switch intentionally omits break keywords // to utilize falling through the cases. switch (units) { case 'year': this.month(0); @@ -1216,18 +1354,18 @@ /* falls through */ } // weeks are a special case if (units === 'week') { - this.day(0); + this.weekday(0); } return this; }, endOf: function (units) { - return this.startOf(units).add(units.replace(/s?$/, 's'), 1).subtract('ms', 1); + return this.startOf(units).add(units, 1).subtract('ms', 1); }, isAfter: function (input, units) { units = typeof units !== 'undefined' ? units : 'millisecond'; return +this.clone().startOf(units) > +moment(input).startOf(units); @@ -1241,33 +1379,89 @@ isSame: function (input, units) { units = typeof units !== 'undefined' ? units : 'millisecond'; return +this.clone().startOf(units) === +moment(input).startOf(units); }, - zone : function () { - return this._isUTC ? 0 : this._d.getTimezoneOffset(); + min: function (other) { + other = moment.apply(null, arguments); + return other < this ? this : other; }, + max: function (other) { + other = moment.apply(null, arguments); + return other > this ? this : other; + }, + + zone : function (input) { + var offset = this._offset || 0; + if (input != null) { + if (typeof input === "string") { + input = timezoneMinutesFromString(input); + } + if (Math.abs(input) < 16) { + input = input * 60; + } + this._offset = input; + this._isUTC = true; + if (offset !== input) { + addOrSubtractDurationFromMoment(this, moment.duration(offset - input, 'm'), 1, true); + } + } else { + return this._isUTC ? offset : this._d.getTimezoneOffset(); + } + return this; + }, + + zoneAbbr : function () { + return this._isUTC ? "UTC" : ""; + }, + + zoneName : function () { + return this._isUTC ? "Coordinated Universal Time" : ""; + }, + daysInMonth : function () { return moment.utc([this.year(), this.month() + 1, 0]).date(); }, dayOfYear : function (input) { var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; return input == null ? dayOfYear : this.add("d", (input - dayOfYear)); }, - isoWeek : function (input) { - var week = weekOfYear(this, 1, 4); - return input == null ? week : this.add("d", (input - week) * 7); + weekYear : function (input) { + var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year; + return input == null ? year : this.add("y", (input - year)); }, + isoWeekYear : function (input) { + var year = weekOfYear(this, 1, 4).year; + return input == null ? year : this.add("y", (input - year)); + }, + week : function (input) { var week = this.lang().week(this); return input == null ? week : this.add("d", (input - week) * 7); }, + isoWeek : function (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add("d", (input - week) * 7); + }, + + weekday : function (input) { + var weekday = (this._d.getDay() + 7 - this.lang()._week.dow) % 7; + return input == null ? weekday : this.add("d", input - weekday); + }, + + isoWeekday : function (input) { + // iso weeks start on monday, which is 1, so we subtract 1 (and add + // 7 for negative mod to work). + var weekday = (this._d.getDay() + 6) % 7; + return input == null ? weekday : this.add("d", input - weekday); + }, + // If passed a language key, it will set the language for this // instance. Otherwise, it will return the language configuration // variables for this instance. lang : function (key) { if (key === undefined) { @@ -1283,10 +1477,11 @@ function makeGetterAndSetter(name, key) { moment.fn[name] = moment.fn[name + 's'] = function (input) { var utc = this._isUTC ? 'UTC' : ''; if (input != null) { this._d['set' + utc + key](input); + moment.updateOffset(this); return this; } else { return this._d['get' + utc + key](); } }; @@ -1300,13 +1495,17 @@ // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear') makeGetterAndSetter('year', 'FullYear'); // add plural methods moment.fn.days = moment.fn.day; + moment.fn.months = moment.fn.month; moment.fn.weeks = moment.fn.week; moment.fn.isoWeeks = moment.fn.isoWeek; + // add aliased format methods + moment.fn.toJSON = moment.fn.toISOString; + /************************************ Duration Prototype ************************************/ @@ -1316,11 +1515,12 @@ }, valueOf : function () { return this._milliseconds + this._days * 864e5 + - this._months * 2592e6; + (this._months % 12) * 2592e6 + + ~~(this._months / 12) * 31536e6; }, humanize : function (withSuffix) { var difference = +this, output = relativeTime(difference, !withSuffix, this.lang()); @@ -1330,10 +1530,41 @@ } return this.lang().postformat(output); }, + add : function (input, val) { + // supports only 2.0-style add(1, 's') or add(moment) + var dur = moment.duration(input, val); + + this._milliseconds += dur._milliseconds; + this._days += dur._days; + this._months += dur._months; + + return this; + }, + + subtract : function (input, val) { + var dur = moment.duration(input, val); + + this._milliseconds -= dur._milliseconds; + this._days -= dur._days; + this._months -= dur._months; + + return this; + }, + + get : function (units) { + units = normalizeUnits(units); + return this[units.toLowerCase() + 's'](); + }, + + as : function (units) { + units = normalizeUnits(units); + return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's'](); + }, + lang : moment.fn.lang }; function makeDurationGetter(name) { moment.duration.fn[name] = function () { @@ -1353,9 +1584,12 @@ makeDurationGetter(i.toLowerCase()); } } makeDurationAsGetter('Weeks', 6048e5); + moment.duration.fn.asMonths = function () { + return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12; + }; /************************************ Default Lang ************************************/