diff options
author | Bernhard Posselt <dev@bernhard-posselt.com> | 2014-03-14 10:22:09 +0100 |
---|---|---|
committer | Bernhard Posselt <dev@bernhard-posselt.com> | 2014-03-26 01:34:31 +0100 |
commit | 2fc5ca4f601174a7ecb7c77a7059f5fac2ab4611 (patch) | |
tree | aa7ab66e29fc7de98533d1e55832ca4fbcd39611 /js/vendor/momentjs/moment.js | |
parent | 22fc777ce7403d706649cf83bb23010dfd7dea04 (diff) |
update a lot of stuff, WIP
Diffstat (limited to 'js/vendor/momentjs/moment.js')
-rw-r--r-- | js/vendor/momentjs/moment.js | 1188 |
1 files changed, 963 insertions, 225 deletions
diff --git a/js/vendor/momentjs/moment.js b/js/vendor/momentjs/moment.js index c8a870e8c..b79da7f26 100644 --- a/js/vendor/momentjs/moment.js +++ b/js/vendor/momentjs/moment.js @@ -1,8 +1,8 @@ -// moment.js -// version : 2.1.0 -// author : Tim Wood -// license : MIT -// momentjs.com +//! moment.js +//! version : 2.5.1 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com (function (undefined) { @@ -11,41 +11,86 @@ ************************************/ var moment, - VERSION = "2.1.0", - round = Math.round, i, + VERSION = "2.5.1", + global = this, + round = Math.round, + i, + + YEAR = 0, + MONTH = 1, + DATE = 2, + HOUR = 3, + MINUTE = 4, + SECOND = 5, + MILLISECOND = 6, + // internal storage for language config files languages = {}, + // moment internal properties + momentProperties = { + _isAMomentObject: null, + _i : null, + _f : null, + _l : null, + _strict : null, + _isUTC : null, + _offset : null, // optional. Combine with _isUTC + _pf : null, + _lang : null // optional + }, + // check for nodeJS - hasModule = (typeof module !== 'undefined' && module.exports), + hasModule = (typeof module !== 'undefined' && module.exports && typeof require !== 'undefined'), // ASP.NET json date format regex aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, - aspNetTimeSpanJsonRegex = /(\-)?(\d*)?\.?(\d+)\:(\d+)\:(\d+)\.?(\d{3})?/, + aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, + + // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html + // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere + isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, // format tokens - 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, + formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g, localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g, // parsing token regexes 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 + parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 + parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 + parseTokenDigits = /\d+/, // nonzero number of digits 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) + parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z + parseTokenT = /T/i, // T (ISO separator) parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 - // preliminary iso regex - // 0000-00-00 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 - isoRegex = /^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/, + //strict parsing regexes + parseTokenOneDigit = /\d/, // 0 - 9 + parseTokenTwoDigits = /\d\d/, // 00 - 99 + parseTokenThreeDigits = /\d{3}/, // 000 - 999 + parseTokenFourDigits = /\d{4}/, // 0000 - 9999 + parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999 + parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf + + // iso 8601 regex + // 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) + 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)?)?$/, + isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', + isoDates = [ + ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], + ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], + ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], + ['GGGG-[W]WW', /\d{4}-W\d{2}/], + ['YYYY-DDD', /\d{4}-\d{3}/] + ], + // iso time formats and regexes isoTimes = [ - ['HH:mm:ss.S', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/], + ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/], ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], ['HH:mm', /(T| )\d\d:\d\d/], ['HH', /(T| )\d\d/] @@ -72,9 +117,24 @@ m : 'minute', h : 'hour', d : 'day', + D : 'date', w : 'week', + W : 'isoWeek', M : 'month', - y : 'year' + y : 'year', + DDD : 'dayOfYear', + e : 'weekday', + E : 'isoWeekday', + gg: 'weekYear', + GG: 'isoWeekYear' + }, + + camelFunctions = { + dayofyear : 'dayOfYear', + isoweekday : 'isoWeekday', + isoweek : 'isoWeek', + weekyear : 'weekYear', + isoweekyear : 'isoWeekYear' }, // format function strings @@ -127,11 +187,15 @@ YYYYY : function () { return leftZeroFill(this.year(), 5); }, + YYYYYY : function () { + var y = this.year(), sign = y >= 0 ? '+' : '-'; + return sign + leftZeroFill(Math.abs(y), 6); + }, gg : function () { return leftZeroFill(this.weekYear() % 100, 2); }, gggg : function () { - return this.weekYear(); + return leftZeroFill(this.weekYear(), 4); }, ggggg : function () { return leftZeroFill(this.weekYear(), 5); @@ -140,7 +204,7 @@ return leftZeroFill(this.isoWeekYear() % 100, 2); }, GGGG : function () { - return this.isoWeekYear(); + return leftZeroFill(this.isoWeekYear(), 4); }, GGGGG : function () { return leftZeroFill(this.isoWeekYear(), 5); @@ -170,14 +234,17 @@ return this.seconds(); }, S : function () { - return ~~(this.milliseconds() / 100); + return toInt(this.milliseconds() / 100); }, SS : function () { - return leftZeroFill(~~(this.milliseconds() / 10), 2); + return leftZeroFill(toInt(this.milliseconds() / 10), 2); }, SSS : function () { return leftZeroFill(this.milliseconds(), 3); }, + SSSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, Z : function () { var a = -this.zone(), b = "+"; @@ -185,7 +252,7 @@ a = -a; b = "-"; } - return b + leftZeroFill(~~(a / 60), 2) + ":" + leftZeroFill(~~a % 60, 2); + return b + leftZeroFill(toInt(a / 60), 2) + ":" + leftZeroFill(toInt(a) % 60, 2); }, ZZ : function () { var a = -this.zone(), @@ -194,7 +261,7 @@ a = -a; b = "-"; } - return b + leftZeroFill(~~(10 * a / 6), 4); + return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); }, z : function () { return this.zoneAbbr(); @@ -204,8 +271,30 @@ }, X : function () { return this.unix(); + }, + Q : function () { + return this.quarter(); } + }, + + lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin']; + + function defaultParsingFlags() { + // We need to deep clone this object, and es5 standard is not very + // helpful. + return { + empty : false, + unusedTokens : [], + unusedInput : [], + overflow : -2, + charsLeftOver : 0, + nullInput : false, + invalidMonth : null, + invalidFormat : false, + userInvalidated : false, + iso: false }; + } function padToken(func, count) { return function (a) { @@ -239,36 +328,35 @@ // Moment prototype object function Moment(config) { + checkOverflow(config); extend(this, config); } // Duration Constructor function Duration(duration) { - var years = duration.years || duration.year || duration.y || 0, - months = duration.months || duration.month || duration.M || 0, - weeks = duration.weeks || duration.week || duration.w || 0, - days = duration.days || duration.day || duration.d || 0, - hours = duration.hours || duration.hour || duration.h || 0, - minutes = duration.minutes || duration.minute || duration.m || 0, - seconds = duration.seconds || duration.second || duration.s || 0, - milliseconds = duration.milliseconds || duration.millisecond || duration.ms || 0; - - // store reference to input for deterministic cloning - this._input = duration; + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; // representation for dateAddRemove - this._milliseconds = milliseconds + + this._milliseconds = +milliseconds + seconds * 1e3 + // 1000 minutes * 6e4 + // 1000 * 60 hours * 36e5; // 1000 * 60 * 60 // Because of dateAddRemove treats 24 hours as different from a // day when working around DST, we need to store them separately - this._days = days + + this._days = +days + weeks * 7; // It is impossible translate months into days without knowing // which months you are are talking about, so we have to store // it separately. - this._months = months + + this._months = +months + years * 12; this._data = {}; @@ -276,7 +364,6 @@ this._bubble(); } - /************************************ Helpers ************************************/ @@ -288,9 +375,29 @@ a[i] = b[i]; } } + + if (b.hasOwnProperty("toString")) { + a.toString = b.toString; + } + + if (b.hasOwnProperty("valueOf")) { + a.valueOf = b.valueOf; + } + return a; } + function cloneMoment(m) { + var result = {}, i; + for (i in m) { + if (m.hasOwnProperty(i) && momentProperties.hasOwnProperty(i)) { + result[i] = m[i]; + } + } + + return result; + } + function absRound(number) { if (number < 0) { return Math.ceil(number); @@ -301,12 +408,14 @@ // left zero fill a number // see http://jsperf.com/left-zero-filling for performance comparison - function leftZeroFill(number, targetLength) { - var output = number + ''; + function leftZeroFill(number, targetLength, forceSign) { + var output = '' + Math.abs(number), + sign = number >= 0; + while (output.length < targetLength) { output = '0' + output; } - return output; + return (sign ? (forceSign ? '+' : '') : '-') + output; } // helper function for _.addTime and _.subtractTime @@ -315,8 +424,7 @@ days = duration._days, months = duration._months, minutes, - hours, - currentDate; + hours; if (milliseconds) { mom._d.setTime(+mom._d + milliseconds * isAdding); @@ -347,14 +455,20 @@ return Object.prototype.toString.call(input) === '[object Array]'; } + function isDate(input) { + return Object.prototype.toString.call(input) === '[object Date]' || + input instanceof Date; + } + // compare two arrays, return the number of differences - function compareArrays(array1, array2) { + function compareArrays(array1, array2, dontConvert) { var len = Math.min(array1.length, array2.length), lengthDiff = Math.abs(array1.length - array2.length), diffs = 0, i; for (i = 0; i < len; i++) { - if (~~array1[i] !== ~~array2[i]) { + if ((dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { diffs++; } } @@ -362,16 +476,155 @@ } function normalizeUnits(units) { - return units ? unitAliases[units] || units.toLowerCase().replace(/(.)s$/, '$1') : units; + if (units) { + var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); + units = unitAliases[units] || camelFunctions[lowered] || lowered; + } + return units; } + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; + + for (prop in inputObject) { + if (inputObject.hasOwnProperty(prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } + + return normalizedInput; + } + + function makeList(field) { + var count, setter; + + if (field.indexOf('week') === 0) { + count = 7; + setter = 'day'; + } + else if (field.indexOf('month') === 0) { + count = 12; + setter = 'month'; + } + else { + return; + } + + moment[field] = function (format, index) { + var i, getter, + method = moment.fn._lang[field], + results = []; + + if (typeof format === 'number') { + index = format; + format = undefined; + } + + getter = function (i) { + var m = moment().utc().set(setter, i); + return method.call(moment.fn._lang, m, format || ''); + }; + + if (index != null) { + return getter(index); + } + else { + for (i = 0; i < count; i++) { + results.push(getter(i)); + } + return results; + } + }; + } + + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; + + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + if (coercedNumber >= 0) { + value = Math.floor(coercedNumber); + } else { + value = Math.ceil(coercedNumber); + } + } + + return value; + } + + function daysInMonth(year, month) { + return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); + } + + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } + + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } + + function checkOverflow(m) { + var overflow; + if (m._a && m._pf.overflow === -2) { + overflow = + m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : + m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : + m._a[HOUR] < 0 || m._a[HOUR] > 23 ? HOUR : + m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : + m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : + m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : + -1; + + if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { + overflow = DATE; + } + + m._pf.overflow = overflow; + } + } + + function isValid(m) { + if (m._isValid == null) { + m._isValid = !isNaN(m._d.getTime()) && + m._pf.overflow < 0 && + !m._pf.empty && + !m._pf.invalidMonth && + !m._pf.nullInput && + !m._pf.invalidFormat && + !m._pf.userInvalidated; + + if (m._strict) { + m._isValid = m._isValid && + m._pf.charsLeftOver === 0 && + m._pf.unusedTokens.length === 0; + } + } + return m._isValid; + } + + function normalizeLanguage(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } + + // Return a moment from input, that is local/utc/zone equivalent to model. + function makeAs(input, model) { + return model._isUTC ? moment(input).zone(model._offset || 0) : + moment(input).local(); + } /************************************ Languages ************************************/ - Language.prototype = { + extend(Language.prototype, { + set : function (config) { var prop, i; for (i in config) { @@ -404,7 +657,7 @@ for (i = 0; i < 12; i++) { // make the regex if we don't have it already if (!this._monthsParse[i]) { - mom = moment([2000, i]); + mom = moment.utc([2000, i]); regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); } @@ -470,7 +723,9 @@ }, isPM : function (input) { - return ((input + '').toLowerCase()[0] === 'p'); + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return ((input + '').toLowerCase().charAt(0) === 'p'); }, _meridiemParse : /[ap]\.?m?\.?/i, @@ -537,11 +792,17 @@ week : function (mom) { 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. + }, + + _invalidDate: 'Invalid date', + invalidDate: function () { + return this._invalidDate; } - }; + }); // Loads a language definition into the `languages` cache. The function // takes a key and optionally values. If not in the browser and no values @@ -556,6 +817,11 @@ return languages[key]; } + // Remove a language from the `languages` cache. Mostly useful in tests. + function unloadLang(key) { + delete languages[key]; + } + // Determines which language definition to use and returns it. // // With no parameters, it will return the global language. If you @@ -563,20 +829,52 @@ // definition for 'en', so long as 'en' has already been loaded using // moment.lang. function getLangDefinition(key) { + var i = 0, j, lang, next, split, + get = function (k) { + if (!languages[k] && hasModule) { + try { + require('./lang/' + k); + } catch (e) { } + } + return languages[k]; + }; + if (!key) { return moment.fn._lang; } - if (!languages[key] && hasModule) { - try { - require('./lang/' + key); - } catch (e) { - // call with no params to set to default - return moment.fn._lang; + + if (!isArray(key)) { + //short-circuit everything else + lang = get(key); + if (lang) { + return lang; } + key = [key]; } - return languages[key]; - } + //pick the language from the array + //try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each + //substring from most specific to least, but move to the next array item if it's a more specific variant than the current root + while (i < key.length) { + split = normalizeLanguage(key[i]).split('-'); + j = split.length; + next = normalizeLanguage(key[i + 1]); + next = next ? next.split('-') : null; + while (j > 0) { + lang = get(split.slice(0, j).join('-')); + if (lang) { + return lang; + } + if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { + //the next array item is better than a shallower substring of this one + break; + } + j--; + } + i++; + } + return moment.fn._lang; + } /************************************ Formatting @@ -584,7 +882,7 @@ function removeFormattingTokens(input) { - if (input.match(/\[.*\]/)) { + if (input.match(/\[[\s\S]/)) { return input.replace(/^\[|\]$/g, ""); } return input.replace(/\\/g, ""); @@ -612,15 +910,12 @@ // format date using native date object function formatMoment(m, format) { - var i = 5; - function replaceLongDateFormatTokens(input) { - return m.lang().longDateFormat(input) || input; + if (!m.isValid()) { + return m.lang().invalidDate(); } - while (i-- && localFormattingTokens.test(format)) { - format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); - } + format = expandFormat(format, m.lang()); if (!formatFunctions[format]) { formatFunctions[format] = makeFormatFunction(format); @@ -629,6 +924,23 @@ return formatFunctions[format](m); } + function expandFormat(format, lang) { + var i = 5; + + function replaceLongDateFormatTokens(input) { + return lang.longDateFormat(input) || input; + } + + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + localFormattingTokens.lastIndex = 0; + i -= 1; + } + + return format; + } + /************************************ Parsing @@ -637,16 +949,32 @@ // get the regex to find the next token function getParseRegexForToken(token, config) { + var a, strict = config._strict; switch (token) { case 'DDDD': return parseTokenThreeDigits; case 'YYYY': - return parseTokenFourDigits; + case 'GGGG': + case 'gggg': + return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; + case 'Y': + case 'G': + case 'g': + return parseTokenSignedNumber; + case 'YYYYYY': case 'YYYYY': - return parseTokenSixDigits; + case 'GGGGG': + case 'ggggg': + return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; case 'S': + if (strict) { return parseTokenOneDigit; } + /* falls through */ case 'SS': + if (strict) { return parseTokenTwoDigits; } + /* falls through */ case 'SSS': + if (strict) { return parseTokenThreeDigits; } + /* falls through */ case 'DDD': return parseTokenOneToThreeDigits; case 'MMM': @@ -665,13 +993,20 @@ return parseTokenTimezone; case 'T': return parseTokenT; + case 'SSSS': + return parseTokenDigits; case 'MM': case 'DD': case 'YY': + case 'GG': + case 'gg': case 'HH': case 'hh': case 'mm': case 'ss': + case 'ww': + case 'WW': + return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; case 'M': case 'D': case 'd': @@ -679,16 +1014,23 @@ case 'h': case 'm': case 's': + case 'w': + case 'W': + case 'e': + case 'E': return parseTokenOneOrTwoDigits; default : - return new RegExp(token.replace('\\', '')); + a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), "i")); + return a; } } function timezoneMinutesFromString(string) { - var tzchunk = (parseTokenTimezone.exec(string) || [])[0], - parts = (tzchunk + '').match(parseTimezoneChunker) || ['-', 0, 0], - minutes = +(parts[1] * 60) + ~~parts[2]; + string = string || ""; + var possibleTzMatches = (string.match(parseTokenTimezone) || []), + tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], + parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], + minutes = +(parts[1] * 60) + toInt(parts[2]); return parts[0] === '+' ? -minutes : minutes; } @@ -701,34 +1043,43 @@ // MONTH case 'M' : // fall through to MM case 'MM' : - datePartArray[1] = (input == null) ? 0 : ~~input - 1; + if (input != null) { + datePartArray[MONTH] = toInt(input) - 1; + } break; case 'MMM' : // fall through to MMMM case 'MMMM' : a = getLangDefinition(config._l).monthsParse(input); // if we didn't find a month name, mark the date as invalid. if (a != null) { - datePartArray[1] = a; + datePartArray[MONTH] = a; } else { - config._isValid = false; + config._pf.invalidMonth = input; } break; // DAY OF MONTH - case 'D' : // fall through to DDDD - case 'DD' : // fall through to DDDD + case 'D' : // fall through to DD + case 'DD' : + if (input != null) { + datePartArray[DATE] = toInt(input); + } + break; + // DAY OF YEAR case 'DDD' : // fall through to DDDD case 'DDDD' : if (input != null) { - datePartArray[2] = ~~input; + config._dayOfYear = toInt(input); } + break; // YEAR case 'YY' : - datePartArray[0] = ~~input + (~~input > 68 ? 1900 : 2000); + datePartArray[YEAR] = toInt(input) + (toInt(input) > 68 ? 1900 : 2000); break; case 'YYYY' : case 'YYYYY' : - datePartArray[0] = ~~input; + case 'YYYYYY' : + datePartArray[YEAR] = toInt(input); break; // AM / PM case 'a' : // fall through to A @@ -740,23 +1091,24 @@ case 'HH' : // fall through to hh case 'h' : // fall through to hh case 'hh' : - datePartArray[3] = ~~input; + datePartArray[HOUR] = toInt(input); break; // MINUTE case 'm' : // fall through to mm case 'mm' : - datePartArray[4] = ~~input; + datePartArray[MINUTE] = toInt(input); break; // SECOND case 's' : // fall through to ss case 'ss' : - datePartArray[5] = ~~input; + datePartArray[SECOND] = toInt(input); break; // MILLISECOND case 'S' : case 'SS' : case 'SSS' : - datePartArray[6] = ~~ (('0.' + input) * 1000); + case 'SSSS' : + datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); break; // UNIX TIMESTAMP WITH MS case 'X': @@ -768,11 +1120,29 @@ config._useUTC = true; config._tzm = timezoneMinutesFromString(input); break; - } - - // if the input is null, the date is not valid - if (input == null) { - config._isValid = false; + case 'w': + case 'ww': + case 'W': + case 'WW': + case 'd': + case 'dd': + case 'ddd': + case 'dddd': + case 'e': + case 'E': + token = token.substr(0, 1); + /* falls through */ + case 'gg': + case 'gggg': + case 'GG': + case 'GGGG': + case 'GGGGG': + token = token.substr(0, 2); + if (input) { + config._w = config._w || {}; + config._w[token] = input; + } + break; } } @@ -780,124 +1150,257 @@ // the array should mirror the parameters below // note: all values past the year are optional and will default to the lowest possible value. // [year, month, day , hour, minute, second, millisecond] - function dateFromArray(config) { - var i, date, input = []; + function dateFromConfig(config) { + var i, date, input = [], currentDate, + yearToUse, fixYear, w, temp, lang, weekday, week; if (config._d) { return; } - for (i = 0; i < 7; i++) { + currentDate = currentDateArray(config); + + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + fixYear = function (val) { + var int_val = parseInt(val, 10); + return val ? + (val.length < 3 ? (int_val > 68 ? 1900 + int_val : 2000 + int_val) : int_val) : + (config._a[YEAR] = |